1/* $NetBSD: mp.c,v 1.7 2021/10/07 12:52:27 msaitoh Exp $ */ 2 3/* 4 * Copyright (c) 2003 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Frank van der Linden for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38#include <sys/cdefs.h> 39__KERNEL_RCSID(0, "$NetBSD: mp.c,v 1.7 2021/10/07 12:52:27 msaitoh Exp $"); 40 41#include "opt_multiprocessor.h" 42#include "opt_acpi.h" 43 44#include "acpica.h" 45#include "ioapic.h" 46#include "pchb.h" 47 48#include <sys/param.h> 49#include <sys/systm.h> 50#include <sys/kernel.h> 51#include <sys/device.h> 52#include <sys/kmem.h> 53#include <sys/queue.h> 54 55#include <machine/specialreg.h> 56#include <machine/cpuvar.h> 57#include <sys/bus.h> 58#include <machine/mpconfig.h> 59 60#include <dev/pci/pcivar.h> 61#include <dev/pci/pcidevs.h> 62 63#include "pci.h" 64#include "locators.h" 65 66#if NIOAPIC > 0 || NACPICA > 0 67#include <machine/mpacpi.h> 68#endif 69 70#if NPCI > 0 71#include <dev/pci/ppbreg.h> 72#endif 73 74#if NIOAPIC > 0 || NACPICA > 0 75static int intr_scan_bus(int, int, intr_handle_t *); 76#if NPCI > 0 77static int intr_find_pcibridge(int, pcitag_t *, pci_chipset_tag_t *); 78#endif 79#endif 80 81#if NPCI > 0 82int 83mp_pci_scan(device_t self, struct pcibus_attach_args *pba, 84 cfprint_t print) 85{ 86 int i, cnt; 87 struct mp_bus *mpb; 88 89 cnt = 0; 90 for (i = 0; i < mp_nbus; i++) { 91 mpb = &mp_busses[i]; 92 if (mpb->mb_name == NULL) 93 continue; 94 if (strcmp(mpb->mb_name, "pci") == 0 && mpb->mb_dev == NULL) { 95 pba->pba_bus = i; 96 mpb->mb_dev = config_found(self, pba, print, 97 CFARGS(.iattr = "pcibus")); 98 cnt++; 99 } 100 } 101 return cnt; 102} 103 104void 105mp_pci_childdetached(device_t self, device_t child) 106{ 107 int i; 108 struct mp_bus *mpb; 109 110 for (i = 0; i < mp_nbus; i++) { 111 mpb = &mp_busses[i]; 112 if (mpb->mb_name == NULL) 113 continue; 114 if (strcmp(mpb->mb_name, "pci") == 0 && mpb->mb_dev == child) 115 mpb->mb_dev = NULL; 116 } 117} 118#endif 119 120/* 121 * List to keep track of PCI buses that are probed but not known 122 * to the firmware. Used to 123 * 124 * XXX should maintain one list, not an array and a linked list. 125 */ 126#if (NPCI > 0) && ((NIOAPIC > 0) || NACPICA > 0) 127struct intr_extra_bus { 128 int bus; 129 pcitag_t *pci_bridge_tag; 130 pci_chipset_tag_t pci_chipset_tag; 131 LIST_ENTRY(intr_extra_bus) list; 132}; 133 134LIST_HEAD(, intr_extra_bus) intr_extra_buses = 135 LIST_HEAD_INITIALIZER(intr_extra_buses); 136 137 138void 139intr_add_pcibus(struct pcibus_attach_args *pba) 140{ 141 struct intr_extra_bus *iebp; 142 143 iebp = kmem_alloc(sizeof(*iebp), KM_SLEEP); 144 iebp->bus = pba->pba_bus; 145 iebp->pci_chipset_tag = pba->pba_pc; 146 iebp->pci_bridge_tag = pba->pba_bridgetag; 147 LIST_INSERT_HEAD(&intr_extra_buses, iebp, list); 148} 149 150static int 151intr_find_pcibridge(int bus, pcitag_t *pci_bridge_tag, 152 pci_chipset_tag_t *pc) 153{ 154 struct intr_extra_bus *iebp; 155 struct mp_bus *mpb; 156 157 if (bus < 0) 158 return ENOENT; 159 160 if (bus < mp_nbus) { 161 mpb = &mp_busses[bus]; 162 if (mpb->mb_pci_bridge_tag == NULL) 163 return ENOENT; 164 *pci_bridge_tag = *mpb->mb_pci_bridge_tag; 165 *pc = mpb->mb_pci_chipset_tag; 166 return 0; 167 } 168 169 LIST_FOREACH(iebp, &intr_extra_buses, list) { 170 if (iebp->bus == bus) { 171 if (iebp->pci_bridge_tag == NULL) 172 return ENOENT; 173 *pci_bridge_tag = *iebp->pci_bridge_tag; 174 *pc = iebp->pci_chipset_tag; 175 return 0; 176 } 177 } 178 return ENOENT; 179} 180#endif 181 182#if NIOAPIC > 0 || NACPICA > 0 183/* 184 * 'pin' argument pci bus_pin encoding of a device/pin combination. 185 */ 186int 187intr_find_mpmapping(int bus, int pin, intr_handle_t *handle) 188{ 189 190#if NPCI > 0 191 while (intr_scan_bus(bus, pin, handle) != 0) { 192 int dev, func; 193 pcitag_t pci_bridge_tag; 194 pci_chipset_tag_t pc; 195 196 if (intr_find_pcibridge(bus, &pci_bridge_tag, &pc) != 0) 197 return ENOENT; 198 dev = pin >> 2; 199 pin = pin & 3; 200 pin = PPB_INTERRUPT_SWIZZLE(pin + 1, dev) - 1; 201 pci_decompose_tag(pc, pci_bridge_tag, &bus, &dev, &func); 202 pin |= (dev << 2); 203 } 204 return 0; 205#else 206 return intr_scan_bus(bus, pin, handle); 207#endif 208} 209 210static int 211intr_scan_bus(int bus, int pin, intr_handle_t *handle) 212{ 213 struct mp_intr_map *mip, *intrs; 214 215 if (bus < 0 || bus >= mp_nbus) 216 return ENOENT; 217 218 intrs = mp_busses[bus].mb_intrs; 219 if (intrs == NULL) 220 return ENOENT; 221 222 for (mip = intrs; mip != NULL; mip = mip->next) { 223 if (mip->bus_pin == pin) { 224#if NACPICA > 0 225 if (mip->linkdev != NULL) 226 if (mpacpi_findintr_linkdev(mip) != 0) 227 continue; 228#endif 229 *handle = mip->ioapic_ih; 230 return 0; 231 } 232 } 233 return ENOENT; 234} 235#endif 236