1c2175767SJohn Baldwin /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 3ebf5747bSPedro F. Giffuni * 4179fa75eSJohn Baldwin * Copyright (c) 2010 Hudson River Trading LLC 5c2175767SJohn Baldwin * Written by: John H. Baldwin <jhb@FreeBSD.org> 6c2175767SJohn Baldwin * All rights reserved. 7c2175767SJohn Baldwin * 8c2175767SJohn Baldwin * Redistribution and use in source and binary forms, with or without 9c2175767SJohn Baldwin * modification, are permitted provided that the following conditions 10c2175767SJohn Baldwin * are met: 11c2175767SJohn Baldwin * 1. Redistributions of source code must retain the above copyright 12c2175767SJohn Baldwin * notice, this list of conditions and the following disclaimer. 13c2175767SJohn Baldwin * 2. Redistributions in binary form must reproduce the above copyright 14c2175767SJohn Baldwin * notice, this list of conditions and the following disclaimer in the 15c2175767SJohn Baldwin * documentation and/or other materials provided with the distribution. 16c2175767SJohn Baldwin * 17c2175767SJohn Baldwin * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18c2175767SJohn Baldwin * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19c2175767SJohn Baldwin * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20c2175767SJohn Baldwin * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21c2175767SJohn Baldwin * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22c2175767SJohn Baldwin * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23c2175767SJohn Baldwin * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24c2175767SJohn Baldwin * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25c2175767SJohn Baldwin * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26c2175767SJohn Baldwin * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27c2175767SJohn Baldwin * SUCH DAMAGE. 28c2175767SJohn Baldwin */ 29c2175767SJohn Baldwin 30c2175767SJohn Baldwin /* 31fd9bc183SKonstantin Belousov * This driver provides a pseudo-bus to enumerate the PCI buses 32fd9bc183SKonstantin Belousov * present on a system using a QPI chipset. It creates a qpi0 bus that 33fd9bc183SKonstantin Belousov * is a child of nexus0 and then creates Host-PCI bridges as a 34c2175767SJohn Baldwin * child of that. 35c2175767SJohn Baldwin */ 36c2175767SJohn Baldwin 37c2175767SJohn Baldwin #include <sys/param.h> 38c2175767SJohn Baldwin #include <sys/bus.h> 39c2175767SJohn Baldwin #include <sys/kernel.h> 40c2175767SJohn Baldwin #include <sys/malloc.h> 41c2175767SJohn Baldwin #include <sys/module.h> 4283c41143SJohn Baldwin #include <sys/rman.h> 43c2175767SJohn Baldwin #include <sys/systm.h> 44c2175767SJohn Baldwin 45c2175767SJohn Baldwin #include <machine/cputypes.h> 46c2175767SJohn Baldwin #include <machine/md_var.h> 4784ca9aadSJohn Baldwin #include <x86/legacyvar.h> 4884ca9aadSJohn Baldwin #include <x86/pci_cfgreg.h> 4984ca9aadSJohn Baldwin #include <x86/specialreg.h> 50c2175767SJohn Baldwin 51e83ea624SJohn Baldwin #include <dev/pci/pcireg.h> 52c2175767SJohn Baldwin #include <dev/pci/pcivar.h> 53c2175767SJohn Baldwin #include <dev/pci/pcib_private.h> 54c2175767SJohn Baldwin #include "pcib_if.h" 55c2175767SJohn Baldwin 56c2175767SJohn Baldwin struct qpi_device { 57c2175767SJohn Baldwin int qd_pcibus; 58c2175767SJohn Baldwin }; 59c2175767SJohn Baldwin 60c2175767SJohn Baldwin static MALLOC_DEFINE(M_QPI, "qpidrv", "qpi system device"); 61c2175767SJohn Baldwin 62c2175767SJohn Baldwin static void 63c2175767SJohn Baldwin qpi_identify(driver_t *driver, device_t parent) 64c2175767SJohn Baldwin { 653c700e2eSKonstantin Belousov int do_qpi; 66c2175767SJohn Baldwin 67c2175767SJohn Baldwin /* Check CPUID to ensure this is an i7 CPU of some sort. */ 683c700e2eSKonstantin Belousov if (cpu_vendor_id != CPU_VENDOR_INTEL || 693c700e2eSKonstantin Belousov CPUID_TO_FAMILY(cpu_id) != 0x6) 703c700e2eSKonstantin Belousov return; 713c700e2eSKonstantin Belousov 723c700e2eSKonstantin Belousov /* Only discover buses with configuration devices if allowed by user */ 733c700e2eSKonstantin Belousov do_qpi = 0; 743c700e2eSKonstantin Belousov TUNABLE_INT_FETCH("hw.attach_intel_csr_pci", &do_qpi); 753c700e2eSKonstantin Belousov if (!do_qpi) 76c2175767SJohn Baldwin return; 77c2175767SJohn Baldwin 78c2175767SJohn Baldwin /* PCI config register access is required. */ 79c2175767SJohn Baldwin if (pci_cfgregopen() == 0) 80c2175767SJohn Baldwin return; 81c2175767SJohn Baldwin 82c2175767SJohn Baldwin /* Add a qpi bus device. */ 83c2175767SJohn Baldwin if (BUS_ADD_CHILD(parent, 20, "qpi", -1) == NULL) 84c2175767SJohn Baldwin panic("Failed to add qpi bus"); 85c2175767SJohn Baldwin } 86c2175767SJohn Baldwin 87c2175767SJohn Baldwin static int 88c2175767SJohn Baldwin qpi_probe(device_t dev) 89c2175767SJohn Baldwin { 90c2175767SJohn Baldwin 91c2175767SJohn Baldwin device_set_desc(dev, "QPI system bus"); 92c2175767SJohn Baldwin return (BUS_PROBE_SPECIFIC); 93c2175767SJohn Baldwin } 94c2175767SJohn Baldwin 95e83ea624SJohn Baldwin /* 96e83ea624SJohn Baldwin * Look for a PCI bus with the specified bus address. If one is found, 97e83ea624SJohn Baldwin * add a pcib device and return 0. Otherwise, return an error code. 98e83ea624SJohn Baldwin */ 99c2175767SJohn Baldwin static int 100e83ea624SJohn Baldwin qpi_probe_pcib(device_t dev, int bus) 101c2175767SJohn Baldwin { 102c2175767SJohn Baldwin struct qpi_device *qdev; 103c2175767SJohn Baldwin device_t child; 104e83ea624SJohn Baldwin uint32_t devid; 1053c700e2eSKonstantin Belousov int s; 106c2175767SJohn Baldwin 107c2175767SJohn Baldwin /* 108e83ea624SJohn Baldwin * If a PCI bus already exists for this bus number, then 109e83ea624SJohn Baldwin * fail. 110c2175767SJohn Baldwin */ 111e83ea624SJohn Baldwin if (pci_find_bsf(bus, 0, 0) != NULL) 112e83ea624SJohn Baldwin return (EEXIST); 113e83ea624SJohn Baldwin 114e83ea624SJohn Baldwin /* 1153c700e2eSKonstantin Belousov * Attempt to read the device id for every slot, function 0 on 1163c700e2eSKonstantin Belousov * the bus. If all read values are 0xffffffff this means that 1173c700e2eSKonstantin Belousov * the bus is not present. 118e83ea624SJohn Baldwin */ 1193c700e2eSKonstantin Belousov for (s = 0; s <= PCI_SLOTMAX; s++) { 1201587a9dbSJohn Baldwin devid = pci_cfgregread(0, bus, s, 0, PCIR_DEVVENDOR, 4); 1213c700e2eSKonstantin Belousov if (devid != 0xffffffff) 1223c700e2eSKonstantin Belousov break; 1233c700e2eSKonstantin Belousov } 124e83ea624SJohn Baldwin if (devid == 0xffffffff) 125e83ea624SJohn Baldwin return (ENOENT); 126e83ea624SJohn Baldwin 127e83ea624SJohn Baldwin if ((devid & 0xffff) != 0x8086) { 1283c700e2eSKonstantin Belousov if (bootverbose) 129e83ea624SJohn Baldwin device_printf(dev, 1303c700e2eSKonstantin Belousov "Device at pci%d.%d.0 has non-Intel vendor 0x%x\n", 1313c700e2eSKonstantin Belousov bus, s, devid & 0xffff); 132e83ea624SJohn Baldwin return (ENXIO); 133e83ea624SJohn Baldwin } 134c2175767SJohn Baldwin 135*a05a6804SWarner Losh child = BUS_ADD_CHILD(dev, 0, "pcib", DEVICE_UNIT_ANY); 136c2175767SJohn Baldwin if (child == NULL) 137e83ea624SJohn Baldwin panic("%s: failed to add pci bus %d", device_get_nameunit(dev), 138e83ea624SJohn Baldwin bus); 139c2175767SJohn Baldwin qdev = malloc(sizeof(struct qpi_device), M_QPI, M_WAITOK); 140e83ea624SJohn Baldwin qdev->qd_pcibus = bus; 141c2175767SJohn Baldwin device_set_ivars(child, qdev); 142e83ea624SJohn Baldwin return (0); 143e83ea624SJohn Baldwin } 144e83ea624SJohn Baldwin 145e83ea624SJohn Baldwin static int 146e83ea624SJohn Baldwin qpi_attach(device_t dev) 147e83ea624SJohn Baldwin { 148e83ea624SJohn Baldwin int bus; 149e83ea624SJohn Baldwin 150e83ea624SJohn Baldwin /* 1513c700e2eSKonstantin Belousov * Each processor socket has a dedicated PCI bus, sometimes 1523c700e2eSKonstantin Belousov * not enumerated by ACPI. Probe all unattached buses from 0 1533c700e2eSKonstantin Belousov * to 255. 154e83ea624SJohn Baldwin */ 1553c700e2eSKonstantin Belousov for (bus = PCI_BUSMAX; bus >= 0; bus--) 1563c700e2eSKonstantin Belousov qpi_probe_pcib(dev, bus); 157c2175767SJohn Baldwin 158c2175767SJohn Baldwin return (bus_generic_attach(dev)); 159c2175767SJohn Baldwin } 160c2175767SJohn Baldwin 161c2175767SJohn Baldwin static int 162c2175767SJohn Baldwin qpi_print_child(device_t bus, device_t child) 163c2175767SJohn Baldwin { 164c2175767SJohn Baldwin struct qpi_device *qdev; 165c2175767SJohn Baldwin int retval = 0; 166c2175767SJohn Baldwin 167c2175767SJohn Baldwin qdev = device_get_ivars(child); 168c2175767SJohn Baldwin retval += bus_print_child_header(bus, child); 169c2175767SJohn Baldwin if (qdev->qd_pcibus != -1) 170c2175767SJohn Baldwin retval += printf(" pcibus %d", qdev->qd_pcibus); 171c2175767SJohn Baldwin retval += bus_print_child_footer(bus, child); 172c2175767SJohn Baldwin 173c2175767SJohn Baldwin return (retval); 174c2175767SJohn Baldwin } 175c2175767SJohn Baldwin 176c2175767SJohn Baldwin static int 177c2175767SJohn Baldwin qpi_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 178c2175767SJohn Baldwin { 179c2175767SJohn Baldwin struct qpi_device *qdev; 180c2175767SJohn Baldwin 181c2175767SJohn Baldwin qdev = device_get_ivars(child); 182c2175767SJohn Baldwin switch (which) { 183c2175767SJohn Baldwin case PCIB_IVAR_BUS: 184c2175767SJohn Baldwin *result = qdev->qd_pcibus; 185c2175767SJohn Baldwin break; 186c2175767SJohn Baldwin default: 187c2175767SJohn Baldwin return (ENOENT); 188c2175767SJohn Baldwin } 189c2175767SJohn Baldwin return (0); 190c2175767SJohn Baldwin } 191c2175767SJohn Baldwin 192c2175767SJohn Baldwin static device_method_t qpi_methods[] = { 193c2175767SJohn Baldwin /* Device interface */ 194c2175767SJohn Baldwin DEVMETHOD(device_identify, qpi_identify), 195c2175767SJohn Baldwin DEVMETHOD(device_probe, qpi_probe), 196c2175767SJohn Baldwin DEVMETHOD(device_attach, qpi_attach), 197c2175767SJohn Baldwin DEVMETHOD(device_shutdown, bus_generic_shutdown), 198c2175767SJohn Baldwin DEVMETHOD(device_suspend, bus_generic_suspend), 199c2175767SJohn Baldwin DEVMETHOD(device_resume, bus_generic_resume), 200c2175767SJohn Baldwin 201c2175767SJohn Baldwin /* Bus interface */ 202c2175767SJohn Baldwin DEVMETHOD(bus_print_child, qpi_print_child), 203c2175767SJohn Baldwin DEVMETHOD(bus_add_child, bus_generic_add_child), 204c2175767SJohn Baldwin DEVMETHOD(bus_read_ivar, qpi_read_ivar), 205c2175767SJohn Baldwin DEVMETHOD(bus_alloc_resource, bus_generic_alloc_resource), 206c2175767SJohn Baldwin DEVMETHOD(bus_release_resource, bus_generic_release_resource), 207c2175767SJohn Baldwin DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 208c2175767SJohn Baldwin DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 209c2175767SJohn Baldwin DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 210c2175767SJohn Baldwin DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 211c2175767SJohn Baldwin { 0, 0 } 212c2175767SJohn Baldwin }; 213c2175767SJohn Baldwin 214c2175767SJohn Baldwin DEFINE_CLASS_0(qpi, qpi_driver, qpi_methods, 0); 21580d2b3deSJohn Baldwin DRIVER_MODULE(qpi, nexus, qpi_driver, 0, 0); 216c2175767SJohn Baldwin 217c2175767SJohn Baldwin static int 218c2175767SJohn Baldwin qpi_pcib_probe(device_t dev) 219c2175767SJohn Baldwin { 220c2175767SJohn Baldwin 221c2175767SJohn Baldwin device_set_desc(dev, "QPI Host-PCI bridge"); 222c2175767SJohn Baldwin return (BUS_PROBE_SPECIFIC); 223c2175767SJohn Baldwin } 224c2175767SJohn Baldwin 225c2175767SJohn Baldwin static int 226c2175767SJohn Baldwin qpi_pcib_attach(device_t dev) 227c2175767SJohn Baldwin { 228c2175767SJohn Baldwin 2295b56413dSWarner Losh device_add_child(dev, "pci", DEVICE_UNIT_ANY); 230c2175767SJohn Baldwin return (bus_generic_attach(dev)); 231c2175767SJohn Baldwin } 232c2175767SJohn Baldwin 233c2175767SJohn Baldwin static int 234c2175767SJohn Baldwin qpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 235c2175767SJohn Baldwin { 236c2175767SJohn Baldwin 237c2175767SJohn Baldwin switch (which) { 238c2175767SJohn Baldwin case PCIB_IVAR_DOMAIN: 239c2175767SJohn Baldwin *result = 0; 240c2175767SJohn Baldwin return (0); 241c2175767SJohn Baldwin case PCIB_IVAR_BUS: 242c2175767SJohn Baldwin *result = pcib_get_bus(dev); 243c2175767SJohn Baldwin return (0); 244c2175767SJohn Baldwin default: 245c2175767SJohn Baldwin return (ENOENT); 246c2175767SJohn Baldwin } 247c2175767SJohn Baldwin } 248c2175767SJohn Baldwin 2494edef187SJohn Baldwin static struct resource * 2504edef187SJohn Baldwin qpi_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid, 2512dd1bdf1SJustin Hibbits rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 2524edef187SJohn Baldwin { 2534edef187SJohn Baldwin 2544edef187SJohn Baldwin if (type == PCI_RES_BUS) 2554edef187SJohn Baldwin return (pci_domain_alloc_bus(0, child, rid, start, end, count, 2564edef187SJohn Baldwin flags)); 2574edef187SJohn Baldwin return (bus_generic_alloc_resource(dev, child, type, rid, start, end, 2584edef187SJohn Baldwin count, flags)); 2594edef187SJohn Baldwin } 2604edef187SJohn Baldwin 261c2175767SJohn Baldwin static int 262c2175767SJohn Baldwin qpi_pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr, 263c2175767SJohn Baldwin uint32_t *data) 264c2175767SJohn Baldwin { 265c2175767SJohn Baldwin device_t bus; 266c2175767SJohn Baldwin 267c2175767SJohn Baldwin bus = device_get_parent(pcib); 268c2175767SJohn Baldwin return (PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data)); 269c2175767SJohn Baldwin } 270c2175767SJohn Baldwin 271c2175767SJohn Baldwin static device_method_t qpi_pcib_methods[] = { 272c2175767SJohn Baldwin /* Device interface */ 273c2175767SJohn Baldwin DEVMETHOD(device_probe, qpi_pcib_probe), 274c2175767SJohn Baldwin DEVMETHOD(device_attach, qpi_pcib_attach), 275c2175767SJohn Baldwin DEVMETHOD(device_shutdown, bus_generic_shutdown), 276c2175767SJohn Baldwin DEVMETHOD(device_suspend, bus_generic_suspend), 277c2175767SJohn Baldwin DEVMETHOD(device_resume, bus_generic_resume), 278c2175767SJohn Baldwin 279c2175767SJohn Baldwin /* Bus interface */ 280c2175767SJohn Baldwin DEVMETHOD(bus_read_ivar, qpi_pcib_read_ivar), 2814edef187SJohn Baldwin DEVMETHOD(bus_alloc_resource, qpi_pcib_alloc_resource), 2824edef187SJohn Baldwin DEVMETHOD(bus_adjust_resource, legacy_pcib_adjust_resource), 2834edef187SJohn Baldwin DEVMETHOD(bus_release_resource, legacy_pcib_release_resource), 28431e15e53SJohn Baldwin DEVMETHOD(bus_activate_resource, legacy_pcib_activate_resource), 28531e15e53SJohn Baldwin DEVMETHOD(bus_deactivate_resource, legacy_pcib_deactivate_resource), 286c2175767SJohn Baldwin DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 287c2175767SJohn Baldwin DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 288c2175767SJohn Baldwin 289c2175767SJohn Baldwin /* pcib interface */ 290c2175767SJohn Baldwin DEVMETHOD(pcib_maxslots, pcib_maxslots), 29184ca9aadSJohn Baldwin DEVMETHOD(pcib_read_config, legacy_pcib_read_config), 29284ca9aadSJohn Baldwin DEVMETHOD(pcib_write_config, legacy_pcib_write_config), 29384ca9aadSJohn Baldwin DEVMETHOD(pcib_alloc_msi, legacy_pcib_alloc_msi), 294c2175767SJohn Baldwin DEVMETHOD(pcib_release_msi, pcib_release_msi), 29584ca9aadSJohn Baldwin DEVMETHOD(pcib_alloc_msix, legacy_pcib_alloc_msix), 296c2175767SJohn Baldwin DEVMETHOD(pcib_release_msix, pcib_release_msix), 297c2175767SJohn Baldwin DEVMETHOD(pcib_map_msi, qpi_pcib_map_msi), 298c2175767SJohn Baldwin 2994b7ec270SMarius Strobl DEVMETHOD_END 300c2175767SJohn Baldwin }; 301c2175767SJohn Baldwin 302c2175767SJohn Baldwin DEFINE_CLASS_0(pcib, qpi_pcib_driver, qpi_pcib_methods, 0); 30380d2b3deSJohn Baldwin DRIVER_MODULE(pcib, qpi, qpi_pcib_driver, 0, 0); 304