1 /* $NetBSD: acpi_pci_machdep.c,v 1.9 2018/12/08 15:04:40 jmcneill Exp $ */ 2 3 /*- 4 * Copyright (c) 2018 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jared McNeill <jmcneill@invisible.ca>. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: acpi_pci_machdep.c,v 1.9 2018/12/08 15:04:40 jmcneill Exp $"); 34 35 #include <sys/param.h> 36 #include <sys/bus.h> 37 #include <sys/device.h> 38 #include <sys/intr.h> 39 #include <sys/systm.h> 40 #include <sys/kernel.h> 41 #include <sys/extent.h> 42 #include <sys/queue.h> 43 #include <sys/mutex.h> 44 #include <sys/kmem.h> 45 46 #include <machine/cpu.h> 47 48 #include <arm/cpufunc.h> 49 50 #include <dev/pci/pcireg.h> 51 #include <dev/pci/pcivar.h> 52 #include <dev/pci/pciconf.h> 53 54 #include <dev/acpi/acpivar.h> 55 #include <dev/acpi/acpi_mcfg.h> 56 #include <dev/acpi/acpi_pci.h> 57 58 #include <arm/acpi/acpi_iort.h> 59 #include <arm/acpi/acpi_pci_machdep.h> 60 61 #include <arm/pci/pci_msi_machdep.h> 62 63 struct acpi_pci_prt { 64 u_int prt_segment; 65 u_int prt_bus; 66 ACPI_HANDLE prt_handle; 67 TAILQ_ENTRY(acpi_pci_prt) prt_list; 68 }; 69 70 static TAILQ_HEAD(, acpi_pci_prt) acpi_pci_irq_routes = 71 TAILQ_HEAD_INITIALIZER(acpi_pci_irq_routes); 72 73 static void acpi_pci_md_attach_hook(device_t, device_t, 74 struct pcibus_attach_args *); 75 static int acpi_pci_md_bus_maxdevs(void *, int); 76 static pcitag_t acpi_pci_md_make_tag(void *, int, int, int); 77 static void acpi_pci_md_decompose_tag(void *, pcitag_t, int *, int *, int *); 78 static u_int acpi_pci_md_get_segment(void *); 79 static uint32_t acpi_pci_md_get_devid(void *, uint32_t); 80 static pcireg_t acpi_pci_md_conf_read(void *, pcitag_t, int); 81 static void acpi_pci_md_conf_write(void *, pcitag_t, int, pcireg_t); 82 static int acpi_pci_md_conf_hook(void *, int, int, int, pcireg_t); 83 static void acpi_pci_md_conf_interrupt(void *, int, int, int, int, int *); 84 85 static int acpi_pci_md_intr_map(const struct pci_attach_args *, 86 pci_intr_handle_t *); 87 static const char *acpi_pci_md_intr_string(void *, pci_intr_handle_t, 88 char *, size_t); 89 static const struct evcnt *acpi_pci_md_intr_evcnt(void *, pci_intr_handle_t); 90 static int acpi_pci_md_intr_setattr(void *, pci_intr_handle_t *, int, 91 uint64_t); 92 static void * acpi_pci_md_intr_establish(void *, pci_intr_handle_t, 93 int, int (*)(void *), void *, 94 const char *); 95 static void acpi_pci_md_intr_disestablish(void *, void *); 96 97 struct arm32_pci_chipset arm_acpi_pci_chipset = { 98 .pc_attach_hook = acpi_pci_md_attach_hook, 99 .pc_bus_maxdevs = acpi_pci_md_bus_maxdevs, 100 .pc_make_tag = acpi_pci_md_make_tag, 101 .pc_decompose_tag = acpi_pci_md_decompose_tag, 102 .pc_get_segment = acpi_pci_md_get_segment, 103 .pc_get_devid = acpi_pci_md_get_devid, 104 .pc_conf_read = acpi_pci_md_conf_read, 105 .pc_conf_write = acpi_pci_md_conf_write, 106 .pc_conf_hook = acpi_pci_md_conf_hook, 107 .pc_conf_interrupt = acpi_pci_md_conf_interrupt, 108 109 .pc_intr_map = acpi_pci_md_intr_map, 110 .pc_intr_string = acpi_pci_md_intr_string, 111 .pc_intr_evcnt = acpi_pci_md_intr_evcnt, 112 .pc_intr_setattr = acpi_pci_md_intr_setattr, 113 .pc_intr_establish = acpi_pci_md_intr_establish, 114 .pc_intr_disestablish = acpi_pci_md_intr_disestablish, 115 }; 116 117 static ACPI_STATUS 118 acpi_pci_md_pci_link(ACPI_HANDLE handle, int bus) 119 { 120 ACPI_PCI_ROUTING_TABLE *prt; 121 ACPI_HANDLE linksrc; 122 ACPI_BUFFER buf; 123 ACPI_STATUS rv; 124 void *linkdev; 125 126 rv = acpi_get(handle, &buf, AcpiGetIrqRoutingTable); 127 if (ACPI_FAILURE(rv)) 128 return rv; 129 130 for (char *p = buf.Pointer; ; p += prt->Length) { 131 prt = (ACPI_PCI_ROUTING_TABLE *)p; 132 if (prt->Length == 0) 133 break; 134 135 const u_int dev = ACPI_HIWORD(prt->Address); 136 if (prt->Source[0] != 0) { 137 aprint_debug("ACPI: %s dev %u INT%c on lnkdev %s\n", 138 acpi_name(handle), dev, 'A' + (prt->Pin & 3), prt->Source); 139 rv = AcpiGetHandle(ACPI_ROOT_OBJECT, prt->Source, &linksrc); 140 if (ACPI_FAILURE(rv)) { 141 aprint_debug("ACPI: AcpiGetHandle failed for '%s': %s\n", 142 prt->Source, AcpiFormatException(rv)); 143 continue; 144 } 145 146 linkdev = acpi_pci_link_devbyhandle(linksrc); 147 acpi_pci_link_add_reference(linkdev, 0, bus, dev, prt->Pin & 3); 148 } else { 149 aprint_debug("ACPI: %s dev %u INT%c on globint %d\n", 150 acpi_name(handle), dev, 'A' + (prt->Pin & 3), prt->SourceIndex); 151 } 152 } 153 154 return AE_OK; 155 } 156 157 static void 158 acpi_pci_md_attach_hook(device_t parent, device_t self, 159 struct pcibus_attach_args *pba) 160 { 161 struct acpi_pci_context *ap = pba->pba_pc->pc_conf_v; 162 struct acpi_pci_prt *prt, *prtp; 163 struct acpi_devnode *ad; 164 ACPI_HANDLE handle; 165 int seg, bus, dev, func; 166 167 seg = ap->ap_seg; 168 handle = NULL; 169 170 if (pba->pba_bridgetag) { 171 /* 172 * Find the PCI address of our parent bridge and look for the 173 * corresponding ACPI device node. If there is no node for this 174 * bus, use the parent bridge routing information. 175 */ 176 acpi_pci_md_decompose_tag(NULL, *pba->pba_bridgetag, &bus, &dev, &func); 177 ad = acpi_pcidev_find(seg, bus, dev, func); 178 if (ad != NULL) { 179 handle = ad->ad_handle; 180 } else { 181 /* No routes defined for this bus, copy from parent */ 182 TAILQ_FOREACH(prtp, &acpi_pci_irq_routes, prt_list) 183 if (prtp->prt_bus == bus) { 184 handle = prtp->prt_handle; 185 break; 186 } 187 } 188 } else { 189 /* 190 * Lookup the ACPI device node for the root bus. 191 */ 192 ad = acpi_pciroot_find(seg, 0); 193 if (ad != NULL) 194 handle = ad->ad_handle; 195 } 196 197 if (handle != NULL) { 198 prt = kmem_alloc(sizeof(*prt), KM_SLEEP); 199 prt->prt_bus = pba->pba_bus; 200 prt->prt_segment = ap->ap_seg; 201 prt->prt_handle = handle; 202 TAILQ_INSERT_TAIL(&acpi_pci_irq_routes, prt, prt_list); 203 } 204 205 acpimcfg_map_bus(self, pba->pba_pc, pba->pba_bus); 206 207 if (ad != NULL) { 208 /* 209 * This is a new ACPI managed bus. Add PCI link references. 210 */ 211 acpi_pci_md_pci_link(ad->ad_handle, pba->pba_bus); 212 } 213 } 214 215 static int 216 acpi_pci_md_bus_maxdevs(void *v, int busno) 217 { 218 return 32; 219 } 220 221 static pcitag_t 222 acpi_pci_md_make_tag(void *v, int b, int d, int f) 223 { 224 return (b << 16) | (d << 11) | (f << 8); 225 } 226 227 static void 228 acpi_pci_md_decompose_tag(void *v, pcitag_t tag, int *bp, int *dp, int *fp) 229 { 230 if (bp) 231 *bp = (tag >> 16) & 0xff; 232 if (dp) 233 *dp = (tag >> 11) & 0x1f; 234 if (fp) 235 *fp = (tag >> 8) & 0x7; 236 } 237 238 static u_int 239 acpi_pci_md_get_segment(void *v) 240 { 241 struct acpi_pci_context * const ap = v; 242 243 return ap->ap_seg; 244 } 245 246 static uint32_t 247 acpi_pci_md_get_devid(void *v, uint32_t devid) 248 { 249 struct acpi_pci_context * const ap = v; 250 251 return acpi_iort_pci_root_map(ap->ap_seg, devid); 252 } 253 254 static pcireg_t 255 acpi_pci_md_conf_read(void *v, pcitag_t tag, int offset) 256 { 257 struct acpi_pci_context * const ap = v; 258 pcireg_t val; 259 260 if (offset < 0 || offset >= PCI_EXTCONF_SIZE) 261 return (pcireg_t) -1; 262 263 acpimcfg_conf_read(&ap->ap_pc, tag, offset, &val); 264 265 return val; 266 } 267 268 static void 269 acpi_pci_md_conf_write(void *v, pcitag_t tag, int offset, pcireg_t val) 270 { 271 struct acpi_pci_context * const ap = v; 272 273 if (offset < 0 || offset >= PCI_EXTCONF_SIZE) 274 return; 275 276 acpimcfg_conf_write(&ap->ap_pc, tag, offset, val); 277 } 278 279 static int 280 acpi_pci_md_conf_hook(void *v, int b, int d, int f, pcireg_t id) 281 { 282 return PCI_CONF_DEFAULT; 283 } 284 285 static void 286 acpi_pci_md_conf_interrupt(void *v, int bus, int dev, int ipin, int sqiz, int *ilinep) 287 { 288 } 289 290 static struct acpi_pci_prt * 291 acpi_pci_md_intr_find_prt(pci_chipset_tag_t pc, u_int bus) 292 { 293 struct acpi_pci_prt *prt, *prtp; 294 u_int segment; 295 296 segment = pci_get_segment(pc); 297 298 prt = NULL; 299 TAILQ_FOREACH(prtp, &acpi_pci_irq_routes, prt_list) 300 if (prtp->prt_segment == segment && prtp->prt_bus == bus) { 301 prt = prtp; 302 break; 303 } 304 305 return prt; 306 } 307 308 static int 309 acpi_pci_md_intr_map(const struct pci_attach_args *pa, pci_intr_handle_t *ih) 310 { 311 struct acpi_pci_prt *prt; 312 ACPI_PCI_ROUTING_TABLE *tab; 313 int line, pol, trig, error; 314 ACPI_HANDLE linksrc; 315 ACPI_BUFFER buf; 316 void *linkdev; 317 318 if (pa->pa_intrpin == PCI_INTERRUPT_PIN_NONE) 319 return EINVAL; 320 321 prt = acpi_pci_md_intr_find_prt(pa->pa_pc, pa->pa_bus); 322 if (prt == NULL) 323 return ENXIO; 324 325 if (ACPI_FAILURE(acpi_get(prt->prt_handle, &buf, AcpiGetIrqRoutingTable))) 326 return EIO; 327 328 error = ENOENT; 329 for (char *p = buf.Pointer; ; p += tab->Length) { 330 tab = (ACPI_PCI_ROUTING_TABLE *)p; 331 if (tab->Length == 0) 332 break; 333 334 if (pa->pa_device == ACPI_HIWORD(tab->Address) && 335 (pa->pa_intrpin - 1) == (tab->Pin & 3)) { 336 if (tab->Source[0] != 0) { 337 if (ACPI_FAILURE(AcpiGetHandle(ACPI_ROOT_OBJECT, tab->Source, &linksrc))) 338 goto done; 339 linkdev = acpi_pci_link_devbyhandle(linksrc); 340 *ih = acpi_pci_link_route_interrupt(linkdev, tab->SourceIndex, 341 &line, &pol, &trig); 342 error = 0; 343 goto done; 344 } else { 345 *ih = tab->SourceIndex; 346 error = 0; 347 goto done; 348 } 349 } 350 } 351 352 done: 353 ACPI_FREE(buf.Pointer); 354 return error; 355 } 356 357 static const char * 358 acpi_pci_md_intr_string(void *v, pci_intr_handle_t ih, char *buf, size_t len) 359 { 360 const int irq = __SHIFTOUT(ih, ARM_PCI_INTR_IRQ); 361 const int vec = __SHIFTOUT(ih, ARM_PCI_INTR_MSI_VEC); 362 363 if (ih & ARM_PCI_INTR_MSIX) 364 snprintf(buf, len, "irq %d (MSI-X vec %d)", irq, vec); 365 else if (ih & ARM_PCI_INTR_MSI) 366 snprintf(buf, len, "irq %d (MSI vec %d)", irq, vec); 367 else 368 snprintf(buf, len, "irq %d", irq); 369 370 return buf; 371 } 372 373 static const struct evcnt * 374 acpi_pci_md_intr_evcnt(void *v, pci_intr_handle_t ih) 375 { 376 return NULL; 377 } 378 379 static int 380 acpi_pci_md_intr_setattr(void *v, pci_intr_handle_t *ih, int attr, uint64_t data) 381 { 382 switch (attr) { 383 case PCI_INTR_MPSAFE: 384 if (data) 385 *ih |= ARM_PCI_INTR_MPSAFE; 386 else 387 *ih &= ~ARM_PCI_INTR_MPSAFE; 388 return 0; 389 default: 390 return ENODEV; 391 } 392 } 393 394 static void * 395 acpi_pci_md_intr_establish(void *v, pci_intr_handle_t ih, int ipl, 396 int (*callback)(void *), void *arg, const char *xname) 397 { 398 struct acpi_pci_context * const ap = v; 399 400 if ((ih & (ARM_PCI_INTR_MSI | ARM_PCI_INTR_MSIX)) != 0) 401 return arm_pci_msi_intr_establish(&ap->ap_pc, ih, ipl, callback, arg, xname); 402 403 const int irq = (int)__SHIFTOUT(ih, ARM_PCI_INTR_IRQ); 404 const int mpsafe = (ih & ARM_PCI_INTR_MPSAFE) ? IST_MPSAFE : 0; 405 406 return intr_establish_xname(irq, ipl, IST_LEVEL | mpsafe, callback, arg, xname); 407 } 408 409 static void 410 acpi_pci_md_intr_disestablish(void *v, void *vih) 411 { 412 intr_disestablish(vih); 413 } 414