1*84b6468dSjmcneill /* $NetBSD: acpipchb.c,v 1.33 2025/01/11 11:40:43 jmcneill Exp $ */ 2e2ed649eSjmcneill 3e2ed649eSjmcneill /*- 4e2ed649eSjmcneill * Copyright (c) 2018 The NetBSD Foundation, Inc. 5e2ed649eSjmcneill * All rights reserved. 6e2ed649eSjmcneill * 7e2ed649eSjmcneill * This code is derived from software contributed to The NetBSD Foundation 8e2ed649eSjmcneill * by Jared McNeill <jmcneill@invisible.ca>. 9e2ed649eSjmcneill * 10e2ed649eSjmcneill * Redistribution and use in source and binary forms, with or without 11e2ed649eSjmcneill * modification, are permitted provided that the following conditions 12e2ed649eSjmcneill * are met: 13e2ed649eSjmcneill * 1. Redistributions of source code must retain the above copyright 14e2ed649eSjmcneill * notice, this list of conditions and the following disclaimer. 15e2ed649eSjmcneill * 2. Redistributions in binary form must reproduce the above copyright 16e2ed649eSjmcneill * notice, this list of conditions and the following disclaimer in the 17e2ed649eSjmcneill * documentation and/or other materials provided with the distribution. 18e2ed649eSjmcneill * 19e2ed649eSjmcneill * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20e2ed649eSjmcneill * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21e2ed649eSjmcneill * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22e2ed649eSjmcneill * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23e2ed649eSjmcneill * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24e2ed649eSjmcneill * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25e2ed649eSjmcneill * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26e2ed649eSjmcneill * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27e2ed649eSjmcneill * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28e2ed649eSjmcneill * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29e2ed649eSjmcneill * POSSIBILITY OF SUCH DAMAGE. 30e2ed649eSjmcneill */ 31e2ed649eSjmcneill 32e2ed649eSjmcneill #include <sys/cdefs.h> 33*84b6468dSjmcneill __KERNEL_RCSID(0, "$NetBSD: acpipchb.c,v 1.33 2025/01/11 11:40:43 jmcneill Exp $"); 34e2ed649eSjmcneill 35e2ed649eSjmcneill #include <sys/param.h> 36e2ed649eSjmcneill #include <sys/bus.h> 37e2ed649eSjmcneill #include <sys/device.h> 38e2ed649eSjmcneill #include <sys/intr.h> 39e2ed649eSjmcneill #include <sys/systm.h> 40e2ed649eSjmcneill #include <sys/kernel.h> 41e2ed649eSjmcneill #include <sys/queue.h> 42e2ed649eSjmcneill #include <sys/mutex.h> 43e2ed649eSjmcneill #include <sys/kmem.h> 44cf660908Sad #include <sys/cpu.h> 45e2ed649eSjmcneill 46e2ed649eSjmcneill #include <arm/cpufunc.h> 47cf79ebbbSjmcneill #include <arm/bootconfig.h> 48e2ed649eSjmcneill 49e2ed649eSjmcneill #include <dev/pci/pcireg.h> 50e2ed649eSjmcneill #include <dev/pci/pcivar.h> 511099f047Sjmcneill #include <dev/pci/pci_resource.h> 52e2ed649eSjmcneill 53e2ed649eSjmcneill #include <dev/acpi/acpivar.h> 54afb4efc1Sjmcneill #include <dev/acpi/acpi_pci.h> 55e2ed649eSjmcneill #include <dev/acpi/acpi_mcfg.h> 56e2ed649eSjmcneill 574fb00351Sjmcneill #include <arm/acpi/acpi_pci_machdep.h> 584fb00351Sjmcneill 598aa946ffSjmcneill #define ACPIPCHB_MAX_RANGES 64 /* XXX arbitrary limit */ 605cc4c843Sjmcneill 618aa946ffSjmcneill struct acpipchb_bus_range { 625cc4c843Sjmcneill bus_addr_t min; 635cc4c843Sjmcneill bus_addr_t max; 645cc4c843Sjmcneill bus_addr_t offset; 658aa946ffSjmcneill }; 668aa946ffSjmcneill 678aa946ffSjmcneill struct acpipchb_bus_space { 688aa946ffSjmcneill struct bus_space bs; 698aa946ffSjmcneill 708aa946ffSjmcneill struct acpipchb_bus_range range[ACPIPCHB_MAX_RANGES]; 718aa946ffSjmcneill int nrange; 725cc4c843Sjmcneill 735cc4c843Sjmcneill int (*map)(void *, bus_addr_t, bus_size_t, 745cc4c843Sjmcneill int, bus_space_handle_t *); 75059f233aSjmcneill 76059f233aSjmcneill int flags; 775cc4c843Sjmcneill }; 785cc4c843Sjmcneill 79e2ed649eSjmcneill struct acpipchb_softc { 80e2ed649eSjmcneill device_t sc_dev; 81e2ed649eSjmcneill 828aa946ffSjmcneill bus_space_tag_t sc_memt; 838aa946ffSjmcneill 84e2ed649eSjmcneill ACPI_HANDLE sc_handle; 85e2ed649eSjmcneill ACPI_INTEGER sc_bus; 86b6813ca1Sjmcneill 878aa946ffSjmcneill struct acpipchb_bus_space sc_pcimem_bst; 885cc4c843Sjmcneill struct acpipchb_bus_space sc_pciio_bst; 89e2ed649eSjmcneill }; 90e2ed649eSjmcneill 91e2ed649eSjmcneill static int acpipchb_match(device_t, cfdata_t, void *); 92e2ed649eSjmcneill static void acpipchb_attach(device_t, device_t, void *); 93e2ed649eSjmcneill 9412a41c4dSjmcneill static void acpipchb_configure_bus(struct acpipchb_softc *, struct pcibus_attach_args *); 95afa9a575Sjmcneill static void acpipchb_setup_ranges(struct acpipchb_softc *, 96afa9a575Sjmcneill struct pcibus_attach_args *); 97afa9a575Sjmcneill static void acpipchb_setup_quirks(struct acpipchb_softc *, 98afa9a575Sjmcneill struct pcibus_attach_args *); 99b6813ca1Sjmcneill 100e2ed649eSjmcneill CFATTACH_DECL_NEW(acpipchb, sizeof(struct acpipchb_softc), 101e2ed649eSjmcneill acpipchb_match, acpipchb_attach, NULL, NULL); 102e2ed649eSjmcneill 103e2ed649eSjmcneill static const char * const compatible[] = { 104e2ed649eSjmcneill "PNP0A08", 105e2ed649eSjmcneill NULL 106e2ed649eSjmcneill }; 107e2ed649eSjmcneill 108e2ed649eSjmcneill static int 109e2ed649eSjmcneill acpipchb_match(device_t parent, cfdata_t cf, void *aux) 110e2ed649eSjmcneill { 111e2ed649eSjmcneill struct acpi_attach_args *aa = aux; 112e2ed649eSjmcneill 113e2ed649eSjmcneill if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE) 114e2ed649eSjmcneill return 0; 115e2ed649eSjmcneill 116e2ed649eSjmcneill return acpi_match_hid(aa->aa_node->ad_devinfo, compatible); 117e2ed649eSjmcneill } 118e2ed649eSjmcneill 119e2ed649eSjmcneill static void 120e2ed649eSjmcneill acpipchb_attach(device_t parent, device_t self, void *aux) 121e2ed649eSjmcneill { 122e2ed649eSjmcneill struct acpipchb_softc * const sc = device_private(self); 123e2ed649eSjmcneill struct acpi_attach_args *aa = aux; 124e2ed649eSjmcneill struct pcibus_attach_args pba; 12586f8722cSjmcneill ACPI_INTEGER seg, nomsi; 126afa9a575Sjmcneill ACPI_STATUS rv; 127b75afbe8Sjmcneill uint16_t bus_start; 1289ebe5263Sjmcneill int val; 129e2ed649eSjmcneill 130e2ed649eSjmcneill sc->sc_dev = self; 1318aa946ffSjmcneill sc->sc_memt = aa->aa_memt; 132e2ed649eSjmcneill sc->sc_handle = aa->aa_node->ad_handle; 133e2ed649eSjmcneill 134b75afbe8Sjmcneill /* 135b75afbe8Sjmcneill * First try to derive the base bus number from _CRS. If that fails, 136b75afbe8Sjmcneill * try _BBN. If that fails too, assume bus 0. 137b75afbe8Sjmcneill */ 138b75afbe8Sjmcneill if (ACPI_SUCCESS(acpi_pcidev_pciroot_bus(sc->sc_handle, &bus_start))) { 139b75afbe8Sjmcneill sc->sc_bus = bus_start; 140b75afbe8Sjmcneill } else { 141afa9a575Sjmcneill rv = acpi_eval_integer(sc->sc_handle, "_BBN", &sc->sc_bus); 142afa9a575Sjmcneill if (ACPI_FAILURE(rv)) { 143e2ed649eSjmcneill sc->sc_bus = 0; 144b75afbe8Sjmcneill } 145afa9a575Sjmcneill } 146e2ed649eSjmcneill 147afa9a575Sjmcneill if (ACPI_FAILURE(acpi_eval_integer(sc->sc_handle, "_SEG", &seg))) { 1484fb00351Sjmcneill seg = 0; 149afa9a575Sjmcneill } 1504fb00351Sjmcneill 15186f8722cSjmcneill if (ACPI_FAILURE(acpi_dsd_integer(sc->sc_handle, "linux,pcie-nomsi", 15286f8722cSjmcneill &nomsi))) { 15386f8722cSjmcneill nomsi = 0; 15486f8722cSjmcneill } 1559ebe5263Sjmcneill if (get_bootconf_option(boot_args, "nopcimsi", 1569ebe5263Sjmcneill BOOTOPT_TYPE_BOOLEAN, &val) && val) { 1579ebe5263Sjmcneill nomsi = 1; 1589ebe5263Sjmcneill } 15986f8722cSjmcneill 160e2ed649eSjmcneill aprint_naive("\n"); 161e2ed649eSjmcneill aprint_normal(": PCI Express Host Bridge\n"); 162e2ed649eSjmcneill 163*84b6468dSjmcneill acpi_claim_childdevs(self, aa->aa_node, NULL); 164e38da568Sjmcneill 165e2ed649eSjmcneill memset(&pba, 0, sizeof(pba)); 166afa9a575Sjmcneill pba.pba_flags = aa->aa_pciflags & 167afa9a575Sjmcneill ~(PCI_FLAGS_MEM_OKAY | PCI_FLAGS_IO_OKAY); 16886f8722cSjmcneill if (nomsi) { 16986f8722cSjmcneill pba.pba_flags &= ~(PCI_FLAGS_MSI_OKAY | PCI_FLAGS_MSIX_OKAY); 17086f8722cSjmcneill } 1718aa946ffSjmcneill pba.pba_memt = 0; 172b6813ca1Sjmcneill pba.pba_iot = 0; 173a496d771Sjmcneill pba.pba_dmat = aa->aa_dmat; 174e2ed649eSjmcneill #ifdef _PCI_HAVE_DMA64 175a496d771Sjmcneill pba.pba_dmat64 = aa->aa_dmat64; 176e2ed649eSjmcneill #endif 1776f25f864Sjmcneill pba.pba_pc = aa->aa_pc; 178e2ed649eSjmcneill pba.pba_bus = sc->sc_bus; 179e2ed649eSjmcneill 1808aa946ffSjmcneill acpipchb_setup_ranges(sc, &pba); 1816f25f864Sjmcneill acpipchb_setup_quirks(sc, &pba); 182b6813ca1Sjmcneill 18312a41c4dSjmcneill acpipchb_configure_bus(sc, &pba); 18412a41c4dSjmcneill 185c66d1ca5Sthorpej config_found(self, &pba, pcibusprint, 186c7fb772bSthorpej CFARGS(.devhandle = device_handle(self))); 187e2ed649eSjmcneill } 188b6813ca1Sjmcneill 18912a41c4dSjmcneill static void 19012a41c4dSjmcneill acpipchb_configure_bus(struct acpipchb_softc *sc, struct pcibus_attach_args *pba) 19112a41c4dSjmcneill { 19212a41c4dSjmcneill struct arm32_pci_chipset *md_pc = 19312a41c4dSjmcneill (struct arm32_pci_chipset *)pba->pba_pc; 19412a41c4dSjmcneill struct acpi_pci_context *ap = md_pc->pc_conf_v; 1951099f047Sjmcneill const bool mapcfgspace = (ap->ap_flags & ACPI_PCI_FLAG_NO_MCFG) == 0; 196cf79ebbbSjmcneill int error, val; 19712a41c4dSjmcneill 198cf79ebbbSjmcneill if (get_bootconf_option(boot_args, "nopciconf", 199cf79ebbbSjmcneill BOOTOPT_TYPE_BOOLEAN, &val) && val) { 200cf79ebbbSjmcneill return; 201cf79ebbbSjmcneill } 20212a41c4dSjmcneill 20312a41c4dSjmcneill error = acpimcfg_configure_bus(sc->sc_dev, pba->pba_pc, sc->sc_handle, 2041099f047Sjmcneill sc->sc_bus, mapcfgspace); 20512a41c4dSjmcneill if (error != 0) { 20612a41c4dSjmcneill aprint_error_dev(sc->sc_dev, "failed to configure bus, error %d\n", 20712a41c4dSjmcneill error); 20812a41c4dSjmcneill } 20912a41c4dSjmcneill } 21012a41c4dSjmcneill 2118aa946ffSjmcneill struct acpipchb_setup_ranges_args { 212b6813ca1Sjmcneill struct acpipchb_softc *sc; 213b6813ca1Sjmcneill struct pcibus_attach_args *pba; 214b6813ca1Sjmcneill }; 215b6813ca1Sjmcneill 2165cc4c843Sjmcneill static int 2175cc4c843Sjmcneill acpipchb_bus_space_map(void *t, bus_addr_t bpa, bus_size_t size, int flag, 2185cc4c843Sjmcneill bus_space_handle_t *bshp) 2195cc4c843Sjmcneill { 2205cc4c843Sjmcneill struct acpipchb_bus_space * const abs = t; 2218aa946ffSjmcneill int i; 2225cc4c843Sjmcneill 2238aa946ffSjmcneill if (size == 0) 2245cc4c843Sjmcneill return ERANGE; 2255cc4c843Sjmcneill 226059f233aSjmcneill if ((abs->flags & PCI_FLAGS_IO_OKAY) != 0) { 227059f233aSjmcneill /* Force strongly ordered mapping for all I/O space */ 2285158b98cSjmcneill flag = BUS_SPACE_MAP_NONPOSTED; 229059f233aSjmcneill } 230059f233aSjmcneill 2318aa946ffSjmcneill for (i = 0; i < abs->nrange; i++) { 2328aa946ffSjmcneill struct acpipchb_bus_range * const range = &abs->range[i]; 233afa9a575Sjmcneill if (bpa >= range->min && bpa + size - 1 <= range->max) { 234afa9a575Sjmcneill return abs->map(t, bpa + range->offset, size, 235afa9a575Sjmcneill flag, bshp); 236afa9a575Sjmcneill } 2378aa946ffSjmcneill } 2388aa946ffSjmcneill 2398aa946ffSjmcneill return ERANGE; 2405cc4c843Sjmcneill } 2415cc4c843Sjmcneill 242b6813ca1Sjmcneill static ACPI_STATUS 2438aa946ffSjmcneill acpipchb_setup_ranges_cb(ACPI_RESOURCE *res, void *ctx) 244b6813ca1Sjmcneill { 2458aa946ffSjmcneill struct acpipchb_setup_ranges_args * const args = ctx; 246b6813ca1Sjmcneill struct acpipchb_softc * const sc = args->sc; 247b6813ca1Sjmcneill struct pcibus_attach_args *pba = args->pba; 2488aa946ffSjmcneill struct acpipchb_bus_space *abs; 2498aa946ffSjmcneill struct acpipchb_bus_range *range; 2508aa946ffSjmcneill const char *range_type; 2518aa946ffSjmcneill u_int pci_flags; 252b6813ca1Sjmcneill 253b6813ca1Sjmcneill if (res->Type != ACPI_RESOURCE_TYPE_ADDRESS32 && 254afa9a575Sjmcneill res->Type != ACPI_RESOURCE_TYPE_ADDRESS64) { 255b6813ca1Sjmcneill return AE_OK; 256afa9a575Sjmcneill } 257b6813ca1Sjmcneill 2588aa946ffSjmcneill switch (res->Data.Address.ResourceType) { 2598aa946ffSjmcneill case ACPI_IO_RANGE: 2608aa946ffSjmcneill abs = &sc->sc_pciio_bst; 2618aa946ffSjmcneill range_type = "I/O"; 2628aa946ffSjmcneill pci_flags = PCI_FLAGS_IO_OKAY; 2638aa946ffSjmcneill break; 2648aa946ffSjmcneill case ACPI_MEMORY_RANGE: 2658aa946ffSjmcneill abs = &sc->sc_pcimem_bst; 2668aa946ffSjmcneill range_type = "MEM"; 2678aa946ffSjmcneill pci_flags = PCI_FLAGS_MEM_OKAY; 2688aa946ffSjmcneill break; 2698aa946ffSjmcneill default: 270b6813ca1Sjmcneill return AE_OK; 271b6813ca1Sjmcneill } 272b6813ca1Sjmcneill 2738aa946ffSjmcneill if (abs->nrange == ACPIPCHB_MAX_RANGES) { 2748aa946ffSjmcneill aprint_error_dev(sc->sc_dev, 275afa9a575Sjmcneill "maximum number of ranges reached (ACPIPCHB_MAX_RANGES)\n"); 276b6813ca1Sjmcneill return AE_LIMIT; 277b6813ca1Sjmcneill } 278b6813ca1Sjmcneill 2798aa946ffSjmcneill range = &abs->range[abs->nrange]; 2808aa946ffSjmcneill switch (res->Type) { 2818aa946ffSjmcneill case ACPI_RESOURCE_TYPE_ADDRESS32: 2828aa946ffSjmcneill range->min = res->Data.Address32.Address.Minimum; 2838aa946ffSjmcneill range->max = res->Data.Address32.Address.Maximum; 2848aa946ffSjmcneill range->offset = res->Data.Address32.Address.TranslationOffset; 2858aa946ffSjmcneill break; 2868aa946ffSjmcneill case ACPI_RESOURCE_TYPE_ADDRESS64: 2878aa946ffSjmcneill range->min = res->Data.Address64.Address.Minimum; 2888aa946ffSjmcneill range->max = res->Data.Address64.Address.Maximum; 2898aa946ffSjmcneill range->offset = res->Data.Address64.Address.TranslationOffset; 2908aa946ffSjmcneill break; 2918aa946ffSjmcneill default: 2928aa946ffSjmcneill return AE_OK; 2938aa946ffSjmcneill } 2948aa946ffSjmcneill abs->nrange++; 2958aa946ffSjmcneill 296afa9a575Sjmcneill aprint_debug_dev(sc->sc_dev, "PCI %s [%#lx-%#lx] -> %#lx\n", 297afa9a575Sjmcneill range_type, range->min, range->max, range->offset); 2988aa946ffSjmcneill 2998aa946ffSjmcneill if ((pba->pba_flags & pci_flags) == 0) { 3008aa946ffSjmcneill abs->bs = *sc->sc_memt; 3018aa946ffSjmcneill abs->bs.bs_cookie = abs; 3028aa946ffSjmcneill abs->map = abs->bs.bs_map; 303059f233aSjmcneill abs->flags = pci_flags; 3048aa946ffSjmcneill abs->bs.bs_map = acpipchb_bus_space_map; 305afa9a575Sjmcneill if ((pci_flags & PCI_FLAGS_IO_OKAY) != 0) { 3068aa946ffSjmcneill pba->pba_iot = &abs->bs; 307afa9a575Sjmcneill } else if ((pci_flags & PCI_FLAGS_MEM_OKAY) != 0) { 3088aa946ffSjmcneill pba->pba_memt = &abs->bs; 309afa9a575Sjmcneill } 3108aa946ffSjmcneill pba->pba_flags |= pci_flags; 3118aa946ffSjmcneill } 3128aa946ffSjmcneill 3138aa946ffSjmcneill return AE_OK; 3148aa946ffSjmcneill } 3158aa946ffSjmcneill 316b6813ca1Sjmcneill static void 3178aa946ffSjmcneill acpipchb_setup_ranges(struct acpipchb_softc *sc, struct pcibus_attach_args *pba) 318b6813ca1Sjmcneill { 3198aa946ffSjmcneill struct acpipchb_setup_ranges_args args; 320b6813ca1Sjmcneill 321b6813ca1Sjmcneill args.sc = sc; 322b6813ca1Sjmcneill args.pba = pba; 323b6813ca1Sjmcneill 324afa9a575Sjmcneill AcpiWalkResources(sc->sc_handle, "_CRS", acpipchb_setup_ranges_cb, 325afa9a575Sjmcneill &args); 326b6813ca1Sjmcneill } 3276f25f864Sjmcneill 3286f25f864Sjmcneill static void 3296f25f864Sjmcneill acpipchb_setup_quirks(struct acpipchb_softc *sc, struct pcibus_attach_args *pba) 3306f25f864Sjmcneill { 331afa9a575Sjmcneill struct arm32_pci_chipset *md_pc = 332afa9a575Sjmcneill (struct arm32_pci_chipset *)pba->pba_pc; 3336f25f864Sjmcneill struct acpi_pci_context *ap = md_pc->pc_conf_v; 3346f25f864Sjmcneill 3356f25f864Sjmcneill pba->pba_flags &= ~ap->ap_pciflags_clear; 3366f25f864Sjmcneill } 337