11558Srgrimes/*- 21558Srgrimes * SPDX-License-Identifier: BSD-2-Clause 31558Srgrimes * 41558Srgrimes * Copyright (C) 2018 Marvell International Ltd. 51558Srgrimes * 61558Srgrimes * Author: Jayachandran C Nair <jchandra@freebsd.org> 71558Srgrimes * 81558Srgrimes * Redistribution and use in source and binary forms, with or without 91558Srgrimes * modification, are permitted provided that the following conditions 101558Srgrimes * are met: 111558Srgrimes * 1. Redistributions of source code must retain the above copyright 121558Srgrimes * notice, this list of conditions and the following disclaimer. 131558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141558Srgrimes * notice, this list of conditions and the following disclaimer in the 151558Srgrimes * documentation and/or other materials provided with the distribution. 161558Srgrimes * 171558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 181558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 211558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271558Srgrimes * SUCH DAMAGE. 281558Srgrimes */ 291558Srgrimes 30114589Sobrien#include "opt_acpi.h" 311558Srgrimes 3238040Scharnier#include <sys/param.h> 331558Srgrimes#include <sys/bus.h> 341558Srgrimes#include <sys/kernel.h> 351558Srgrimes#include <sys/malloc.h> 361558Srgrimes 371558Srgrimes#include <machine/intr.h> 381558Srgrimes 39114589Sobrien#include <contrib/dev/acpica/include/acpi.h> 4038040Scharnier#include <contrib/dev/acpica/include/accommon.h> 41114589Sobrien#include <contrib/dev/acpica/include/actables.h> 42114589Sobrien 431558Srgrimes#include <dev/acpica/acpivar.h> 441558Srgrimes 45102231Strhodes/* 461558Srgrimes * Track next XREF available for ITS groups. 471558Srgrimes */ 4842873Sluoqistatic u_int acpi_its_xref = ACPI_MSI_XREF; 4996478Sphk 501558Srgrimes/* 511558Srgrimes * Some types of IORT nodes have a set of mappings. Each of them map 5298542Smckusick * a range of device IDs [base..end] from the current node to another 5398542Smckusick * node. The corresponding device IDs on destination node starts at 541558Srgrimes * outbase. 55207141Sjeff */ 561558Srgrimesstruct iort_map_entry { 57110174Sgordon u_int base; 581558Srgrimes u_int end; 591558Srgrimes u_int outbase; 601558Srgrimes u_int flags; 61109597Sjmallett u_int out_node_offset; 6238040Scharnier struct iort_node *out_node; 631558Srgrimes}; 641558Srgrimes 65207141Sjeff/* 6658047Ssheldonh * The ITS group node does not have any outgoing mappings. It has a 67226266Smckusick * of a list of GIC ITS blocks which can handle the device ID. We 681558Srgrimes * will store the PIC XREF used by the block and the blocks proximity 691558Srgrimes * data here, so that it can be retrieved together. 701558Srgrimes */ 711558Srgrimesstruct iort_its_entry { 721558Srgrimes u_int its_id; 73227081Sed u_int xref; 74109597Sjmallett int pxm; 751558Srgrimes}; 7692883Simp 7792883Simpstruct iort_named_component 78207141Sjeff{ 79207141Sjeff UINT32 NodeFlags; 80207141Sjeff UINT64 MemoryProperties; 811558Srgrimes UINT8 MemoryAddressLimit; 821558Srgrimes char DeviceName[32]; /* Path of namespace object */ 83109597Sjmallett}; 841558Srgrimes 85207141Sjeff/* 86216798Skib * IORT node. Each node has some device specific data depending on the 87109963Sjmallett * type of the node. The node can also have a set of mappings, OR in 8879750Sdd * case of ITS group nodes a set of ITS entries. 89127455Sbde * The nodes are kept in a TAILQ by type. 90207141Sjeff */ 91207141Sjeffstruct iort_node { 92216798Skib TAILQ_ENTRY(iort_node) next; /* next entry with same type */ 93207141Sjeff enum AcpiIortNodeType type; /* ACPI type */ 94127441Sbde u_int node_offset; /* offset in IORT - node ID */ 9579750Sdd u_int nentries; /* items in array below */ 9642873Sluoqi u_int usecount; /* for bookkeeping */ 9742873Sluoqi u_int revision; /* node revision */ 981558Srgrimes union { 99127441Sbde struct iort_map_entry *mappings; /* node mappings */ 100127441Sbde struct iort_its_entry *its; /* ITS IDs array */ 101207141Sjeff } entries; 102216798Skib union { 103207141Sjeff ACPI_IORT_ROOT_COMPLEX pci_rc; /* PCI root complex */ 104207141Sjeff ACPI_IORT_SMMU smmu; 105127455Sbde ACPI_IORT_SMMU_V3 smmu_v3; 106127441Sbde struct iort_named_component named_comp; 107216798Skib } data; 108216798Skib}; 109127441Sbde 110127441Sbde/* Lists for each of the types. */ 111127441Sbdestatic TAILQ_HEAD(, iort_node) pci_nodes = TAILQ_HEAD_INITIALIZER(pci_nodes); 112127441Sbdestatic TAILQ_HEAD(, iort_node) smmu_nodes = TAILQ_HEAD_INITIALIZER(smmu_nodes); 113127441Sbdestatic TAILQ_HEAD(, iort_node) its_groups = TAILQ_HEAD_INITIALIZER(its_groups); 114127441Sbdestatic TAILQ_HEAD(, iort_node) named_nodes = TAILQ_HEAD_INITIALIZER(named_nodes); 115127441Sbde 116127441Sbdestatic int 117127441Sbdeiort_entry_get_id_mapping_index(struct iort_node *node) 118200796Strasz{ 119127441Sbde 120127441Sbde switch(node->type) { 121127441Sbde case ACPI_IORT_NODE_SMMU_V3: 122127441Sbde /* The ID mapping field was added in version 1 */ 123127441Sbde if (node->revision < 1) 124127441Sbde return (-1); 125127441Sbde 126127441Sbde /* 127127441Sbde * If all the control interrupts are GISCV based the ID 128127441Sbde * mapping field is ignored. 129127441Sbde */ 130127441Sbde if (node->data.smmu_v3.EventGsiv != 0 && 131127441Sbde node->data.smmu_v3.PriGsiv != 0 && 132127441Sbde node->data.smmu_v3.GerrGsiv != 0 && 133127441Sbde node->data.smmu_v3.SyncGsiv != 0) 134127441Sbde return (-1); 135127441Sbde 136127441Sbde if (node->data.smmu_v3.IdMappingIndex >= node->nentries) 137127441Sbde return (-1); 138127441Sbde 139127441Sbde return (node->data.smmu_v3.IdMappingIndex); 140127441Sbde case ACPI_IORT_NODE_PMCG: 141127441Sbde return (0); 142127441Sbde default: 143127441Sbde break; 144127441Sbde } 145127441Sbde 146127441Sbde return (-1); 147127441Sbde} 148207141Sjeff 149207141Sjeff/* 150207141Sjeff * Lookup an ID in the mappings array. If successful, map the input ID 151207141Sjeff * to the output ID and return the output node found. 152207141Sjeff */ 153207141Sjeffstatic struct iort_node * 154207141Sjeffiort_entry_lookup(struct iort_node *node, u_int id, u_int *outid) 155207141Sjeff{ 156207141Sjeff struct iort_map_entry *entry; 157207141Sjeff int i, id_map; 158207141Sjeff 159207141Sjeff id_map = iort_entry_get_id_mapping_index(node); 160163842Spjd entry = node->entries.mappings; 161163842Spjd for (i = 0; i < node->nentries; i++, entry++) { 162163842Spjd if (i == id_map) 163163842Spjd continue; 164163842Spjd if (entry->base <= id && id <= entry->end) 165163842Spjd break; 166163842Spjd } 167163842Spjd if (i == node->nentries) 168163842Spjd return (NULL); 169163842Spjd if ((entry->flags & ACPI_IORT_ID_SINGLE_MAPPING) == 0) 170163842Spjd *outid = entry->outbase + (id - entry->base); 171163842Spjd else 172163842Spjd *outid = entry->outbase; 173127441Sbde return (entry->out_node); 174127441Sbde} 175127441Sbde 176127441Sbde/* 177127441Sbde * Perform an additional lookup in case of SMMU node and ITS outtype. 178127441Sbde */ 179127441Sbdestatic struct iort_node * 180127441Sbdeiort_smmu_trymap(struct iort_node *node, u_int outtype, u_int *outid) 181127441Sbde{ 182127441Sbde /* Original node can be not found. */ 183127441Sbde if (!node) 184127441Sbde return (NULL); 185127441Sbde 186127441Sbde /* Node can be SMMU or ITS. If SMMU, we need another lookup. */ 187127441Sbde if (outtype == ACPI_IORT_NODE_ITS_GROUP && 188127441Sbde (node->type == ACPI_IORT_NODE_SMMU_V3 || 189127441Sbde node->type == ACPI_IORT_NODE_SMMU)) { 190127441Sbde node = iort_entry_lookup(node, *outid, outid); 191127441Sbde if (node == NULL) 192127441Sbde return (NULL); 193127441Sbde } 194127441Sbde 195127441Sbde KASSERT(node->type == outtype, ("mapping fail")); 196127441Sbde return (node); 197127441Sbde} 198127441Sbde 199127441Sbde/* 200127441Sbde * Map a PCI RID to a SMMU node or an ITS node, based on outtype. 201127441Sbde */ 202127441Sbdestatic struct iort_node * 203127441Sbdeiort_pci_rc_map(u_int seg, u_int rid, u_int outtype, u_int *outid) 204127441Sbde{ 205127441Sbde struct iort_node *node, *out_node; 206127441Sbde u_int nxtid; 207127441Sbde 208127441Sbde out_node = NULL; 209127441Sbde TAILQ_FOREACH(node, &pci_nodes, next) { 210127441Sbde if (node->data.pci_rc.PciSegmentNumber != seg) 211127441Sbde continue; 212200796Strasz out_node = iort_entry_lookup(node, rid, &nxtid); 213200796Strasz if (out_node != NULL) 214200796Strasz break; 215200796Strasz } 216200796Strasz 217200796Strasz out_node = iort_smmu_trymap(out_node, outtype, &nxtid); 218200796Strasz if (out_node) 219200796Strasz *outid = nxtid; 220200796Strasz 221200796Strasz return (out_node); 222200796Strasz} 223200796Strasz 224127441Sbde/* 225127441Sbde * Map a named component node to a SMMU node or an ITS node, based on outtype. 226127441Sbde */ 227127441Sbdestatic struct iort_node * 228127455Sbdeiort_named_comp_map(const char *devname, u_int rid, u_int outtype, u_int *outid) 229127455Sbde{ 230127441Sbde struct iort_node *node, *out_node; 231127441Sbde u_int nxtid; 232127441Sbde 233127441Sbde out_node = NULL; 234127441Sbde TAILQ_FOREACH(node, &named_nodes, next) { 235127441Sbde if (strstr(node->data.named_comp.DeviceName, devname) == NULL) 236127441Sbde continue; 237127441Sbde out_node = iort_entry_lookup(node, rid, &nxtid); 238127441Sbde if (out_node != NULL) 239127455Sbde break; 240127441Sbde } 241127455Sbde 242127441Sbde out_node = iort_smmu_trymap(out_node, outtype, &nxtid); 243127441Sbde if (out_node) 244127441Sbde *outid = nxtid; 245127441Sbde 246127441Sbde return (out_node); 247127441Sbde} 248127441Sbde 249127441Sbde#ifdef notyet 250127441Sbde/* 251127441Sbde * Not implemented, map a PCIe device to the SMMU it is associated with. 252127441Sbde */ 253127441Sbdeint 254127441Sbdeacpi_iort_map_smmu(u_int seg, u_int devid, void **smmu, u_int *sid) 255127441Sbde{ 256127441Sbde /* XXX: convert oref to SMMU device */ 257127441Sbde return (ENXIO); 258127441Sbde} 259127441Sbde#endif 260127441Sbde 261127441Sbde/* 262127441Sbde * Allocate memory for a node, initialize and copy mappings. 'start' 263127441Sbde * argument provides the table start used to calculate the node offset. 264127441Sbde */ 265207141Sjeffstatic void 266207141Sjeffiort_copy_data(struct iort_node *node, ACPI_IORT_NODE *node_entry) 267207141Sjeff{ 268207141Sjeff ACPI_IORT_ID_MAPPING *map_entry; 269207141Sjeff struct iort_map_entry *mapping; 270207141Sjeff int i; 271207141Sjeff 272207141Sjeff map_entry = ACPI_ADD_PTR(ACPI_IORT_ID_MAPPING, node_entry, 273207141Sjeff node_entry->MappingOffset); 274207141Sjeff node->nentries = node_entry->MappingCount; 275216798Skib node->usecount = 0; 276216798Skib mapping = malloc(sizeof(*mapping) * node->nentries, M_DEVBUF, 277216798Skib M_WAITOK | M_ZERO); 278216798Skib node->entries.mappings = mapping; 279216798Skib for (i = 0; i < node->nentries; i++, mapping++, map_entry++) { 280216798Skib mapping->base = map_entry->InputBase; 281216798Skib /* 282216798Skib * IdCount means "The number of IDs in the range minus one" (ARM DEN 0049D). 283216798Skib * We use <= for comparison against this field, so don't add one here. 284216798Skib */ 285216798Skib mapping->end = map_entry->InputBase + map_entry->IdCount; 286216798Skib mapping->outbase = map_entry->OutputBase; 287127441Sbde mapping->out_node_offset = map_entry->OutputReference; 288127441Sbde mapping->flags = map_entry->Flags; 289105120Srwatson mapping->out_node = NULL; 29069314Scharnier } 29169314Scharnier} 29269314Scharnier 293127441Sbde/* 29469314Scharnier * Allocate and copy an ITS group. 295109963Sjmallett */ 296109963Sjmallettstatic void 297109963Sjmallettiort_copy_its(struct iort_node *node, ACPI_IORT_NODE *node_entry) 298109963Sjmallett{ 299207421Sjeff struct iort_its_entry *its; 300207421Sjeff ACPI_IORT_ITS_GROUP *itsg_entry; 301207421Sjeff UINT32 *id; 30269829Scharnier int i; 30369829Scharnier 30469829Scharnier itsg_entry = (ACPI_IORT_ITS_GROUP *)node_entry->NodeData; 30569829Scharnier node->nentries = itsg_entry->ItsCount; 30669829Scharnier node->usecount = 0; 30769829Scharnier its = malloc(sizeof(*its) * node->nentries, M_DEVBUF, M_WAITOK | M_ZERO); 30869829Scharnier node->entries.its = its; 309110174Sgordon id = &itsg_entry->Identifiers[0]; 310110174Sgordon for (i = 0; i < node->nentries; i++, its++, id++) { 311110174Sgordon its->its_id = *id; 312110174Sgordon its->pxm = -1; 313105120Srwatson its->xref = 0; 314200796Strasz } 315105120Srwatson} 316105120Srwatson 317105120Srwatson/* 318200796Strasz * Walk the IORT table and add nodes to corresponding list. 319200796Strasz */ 320200796Straszstatic void 321105120Srwatsoniort_add_nodes(ACPI_IORT_NODE *node_entry, u_int node_offset) 322105120Srwatson{ 323105120Srwatson ACPI_IORT_ROOT_COMPLEX *pci_rc; 324105120Srwatson ACPI_IORT_SMMU *smmu; 325105120Srwatson ACPI_IORT_SMMU_V3 *smmu_v3; 326105120Srwatson ACPI_IORT_NAMED_COMPONENT *named_comp; 327105120Srwatson struct iort_node *node; 328105120Srwatson 329105120Srwatson node = malloc(sizeof(*node), M_DEVBUF, M_WAITOK | M_ZERO); 330105120Srwatson node->type = node_entry->Type; 331105120Srwatson node->node_offset = node_offset; 332105206Srwatson node->revision = node_entry->Revision; 333105120Srwatson 334105120Srwatson /* copy nodes depending on type */ 335105120Srwatson switch(node_entry->Type) { 33669829Scharnier case ACPI_IORT_NODE_PCI_ROOT_COMPLEX: 33769829Scharnier pci_rc = (ACPI_IORT_ROOT_COMPLEX *)node_entry->NodeData; 338127455Sbde memcpy(&node->data.pci_rc, pci_rc, sizeof(*pci_rc)); 33969829Scharnier iort_copy_data(node, node_entry); 34069829Scharnier TAILQ_INSERT_TAIL(&pci_nodes, node, next); 34169829Scharnier break; 342127455Sbde case ACPI_IORT_NODE_SMMU: 34369829Scharnier smmu = (ACPI_IORT_SMMU *)node_entry->NodeData; 34469829Scharnier memcpy(&node->data.smmu, smmu, sizeof(*smmu)); 34569829Scharnier iort_copy_data(node, node_entry); 34675377Smckusick TAILQ_INSERT_TAIL(&smmu_nodes, node, next); 34775377Smckusick break; 348203769Smckusick case ACPI_IORT_NODE_SMMU_V3: 34975377Smckusick smmu_v3 = (ACPI_IORT_SMMU_V3 *)node_entry->NodeData; 35075377Smckusick memcpy(&node->data.smmu_v3, smmu_v3, sizeof(*smmu_v3)); 35175377Smckusick iort_copy_data(node, node_entry); 35275377Smckusick TAILQ_INSERT_TAIL(&smmu_nodes, node, next); 35375377Smckusick break; 35475377Smckusick case ACPI_IORT_NODE_ITS_GROUP: 35575377Smckusick iort_copy_its(node, node_entry); 35675377Smckusick TAILQ_INSERT_TAIL(&its_groups, node, next); 357207141Sjeff break; 358207141Sjeff case ACPI_IORT_NODE_NAMED_COMPONENT: 359207141Sjeff named_comp = (ACPI_IORT_NAMED_COMPONENT *)node_entry->NodeData; 360207141Sjeff memcpy(&node->data.named_comp, named_comp, sizeof(*named_comp)); 361207141Sjeff 362207141Sjeff /* Copy name of the node separately. */ 363207141Sjeff strncpy(node->data.named_comp.DeviceName, 364207141Sjeff named_comp->DeviceName, 365207141Sjeff sizeof(node->data.named_comp.DeviceName)); 366207141Sjeff node->data.named_comp.DeviceName[31] = 0; 367207141Sjeff 368207141Sjeff iort_copy_data(node, node_entry); 369207141Sjeff TAILQ_INSERT_TAIL(&named_nodes, node, next); 370207141Sjeff break; 371207141Sjeff default: 372207141Sjeff printf("ACPI: IORT: Dropping unhandled type %u\n", 373207141Sjeff node_entry->Type); 374207141Sjeff free(node, M_DEVBUF); 375207141Sjeff break; 376207141Sjeff } 377208241Sjeff} 378207141Sjeff 379208241Sjeff/* 380208241Sjeff * For the mapping entry given, walk thru all the possible destination 381208241Sjeff * nodes and resolve the output reference. 382208241Sjeff */ 383207141Sjeffstatic void 384207141Sjeffiort_resolve_node(struct iort_map_entry *entry, int check_smmu) 385207141Sjeff{ 386163842Spjd struct iort_node *node, *np; 387163842Spjd 388163842Spjd node = NULL; 389163842Spjd if (check_smmu) { 390163842Spjd TAILQ_FOREACH(np, &smmu_nodes, next) { 391163842Spjd if (entry->out_node_offset == np->node_offset) { 392163842Spjd node = np; 393163842Spjd break; 394163842Spjd } 395163842Spjd } 396163842Spjd } 397163842Spjd if (node == NULL) { 398163842Spjd TAILQ_FOREACH(np, &its_groups, next) { 399163842Spjd if (entry->out_node_offset == np->node_offset) { 400163842Spjd node = np; 401163842Spjd break; 402163842Spjd } 403163842Spjd } 404163842Spjd } 405163842Spjd if (node != NULL) { 406105120Srwatson node->usecount++; 407105120Srwatson entry->out_node = node; 408105120Srwatson } else { 409105120Srwatson printf("ACPI: IORT: Firmware Bug: no mapping for node %u\n", 410105120Srwatson entry->out_node_offset); 411105120Srwatson } 412105120Srwatson} 413105120Srwatson 414105120Srwatson/* 415105120Srwatson * Resolve all output node references to node pointers. 416105120Srwatson */ 417105120Srwatsonstatic void 418105120Srwatsoniort_post_process_mappings(void) 419105120Srwatson{ 420105120Srwatson struct iort_node *node; 421105120Srwatson int i; 422105206Srwatson 423105120Srwatson TAILQ_FOREACH(node, &pci_nodes, next) 424105120Srwatson for (i = 0; i < node->nentries; i++) 425105120Srwatson iort_resolve_node(&node->entries.mappings[i], TRUE); 42669829Scharnier TAILQ_FOREACH(node, &smmu_nodes, next) 42769829Scharnier for (i = 0; i < node->nentries; i++) 428127455Sbde iort_resolve_node(&node->entries.mappings[i], FALSE); 42969829Scharnier TAILQ_FOREACH(node, &named_nodes, next) 43069829Scharnier for (i = 0; i < node->nentries; i++) 43169829Scharnier iort_resolve_node(&node->entries.mappings[i], TRUE); 43269829Scharnier} 43369829Scharnier 43469829Scharnier/* 43569829Scharnier * Walk MADT table, assign PIC xrefs to all ITS entries. 43669829Scharnier */ 43769829Scharnierstatic void 43869829Scharniermadt_resolve_its_xref(ACPI_SUBTABLE_HEADER *entry, void *arg) 43969829Scharnier{ 440200796Strasz ACPI_MADT_GENERIC_TRANSLATOR *gict; 441200796Strasz struct iort_node *its_node; 442200796Strasz struct iort_its_entry *its_entry; 443200796Strasz u_int xref; 444200796Strasz int i, matches; 445200796Strasz 446200796Strasz if (entry->Type != ACPI_MADT_TYPE_GENERIC_TRANSLATOR) 447200796Strasz return; 448200796Strasz 449200796Strasz gict = (ACPI_MADT_GENERIC_TRANSLATOR *)entry; 450200796Strasz matches = 0; 451200796Strasz xref = acpi_its_xref++; 452200796Strasz TAILQ_FOREACH(its_node, &its_groups, next) { 453200796Strasz its_entry = its_node->entries.its; 454200796Strasz for (i = 0; i < its_node->nentries; i++, its_entry++) { 455200796Strasz if (its_entry->its_id == gict->TranslationId) { 456200796Strasz its_entry->xref = xref; 457200796Strasz matches++; 458200796Strasz } 459200796Strasz } 460200796Strasz } 461200796Strasz if (matches == 0) 462200796Strasz printf("ACPI: IORT: Unused ITS block, ID %u\n", 46369829Scharnier gict->TranslationId); 46469829Scharnier} 46569829Scharnier 466127455Sbde/* 46769829Scharnier * Walk SRAT, assign proximity to all ITS entries. 468127455Sbde */ 46975498Smckusickstatic void 47075498Smckusicksrat_resolve_its_pxm(ACPI_SUBTABLE_HEADER *entry, void *arg) 47169829Scharnier{ 47269829Scharnier ACPI_SRAT_GIC_ITS_AFFINITY *gicits; 47369829Scharnier struct iort_node *its_node; 47469829Scharnier struct iort_its_entry *its_entry; 47569829Scharnier int *map_counts; 476127455Sbde int i, matches, dom; 47769829Scharnier 478127455Sbde if (entry->Type != ACPI_SRAT_TYPE_GIC_ITS_AFFINITY) 47969829Scharnier return; 48069829Scharnier 48169829Scharnier matches = 0; 48269829Scharnier map_counts = arg; 48369829Scharnier gicits = (ACPI_SRAT_GIC_ITS_AFFINITY *)entry; 48469829Scharnier dom = acpi_map_pxm_to_vm_domainid(gicits->ProximityDomain); 48569829Scharnier 48669829Scharnier /* 48769829Scharnier * Catch firmware and config errors. map_counts keeps a 488127455Sbde * count of ProximityDomain values mapping to a domain ID 48969829Scharnier */ 49069829Scharnier#if MAXMEMDOM > 1 49169829Scharnier if (dom == -1) 49269829Scharnier printf("Firmware Error: Proximity Domain %d could not be" 49369829Scharnier " mapped for GIC ITS ID %d!\n", 49469829Scharnier gicits->ProximityDomain, gicits->ItsId); 495127455Sbde#endif 49669829Scharnier /* use dom + 1 as index to handle the case where dom == -1 */ 497127455Sbde i = ++map_counts[dom + 1]; 49869829Scharnier if (i > 1) { 49969829Scharnier#ifdef NUMA 50069829Scharnier if (dom != -1) 50175377Smckusick printf("ERROR: Multiple Proximity Domains map to the" 50275377Smckusick " same NUMA domain %d!\n", dom); 503203769Smckusick#else 50475377Smckusick printf("WARNING: multiple Proximity Domains in SRAT but NUMA" 50575377Smckusick " NOT enabled!\n"); 50675377Smckusick#endif 50775377Smckusick } 50875377Smckusick TAILQ_FOREACH(its_node, &its_groups, next) { 50975377Smckusick its_entry = its_node->entries.its; 51075377Smckusick for (i = 0; i < its_node->nentries; i++, its_entry++) { 51175377Smckusick if (its_entry->its_id == gicits->ItsId) { 512216798Skib its_entry->pxm = dom; 513216798Skib matches++; 514216798Skib } 515216798Skib } 516216798Skib } 517216798Skib if (matches == 0) 518216798Skib printf("ACPI: IORT: ITS block %u in SRAT not found in IORT!\n", 519216798Skib gicits->ItsId); 520216798Skib} 521216798Skib 522216798Skib/* 523216798Skib * Cross check the ITS Id with MADT and (if available) SRAT. 524216798Skib */ 525216798Skibstatic int 526216798Skibiort_post_process_its(void) 527216798Skib{ 528216798Skib ACPI_TABLE_MADT *madt; 529216798Skib ACPI_TABLE_SRAT *srat; 53069829Scharnier vm_paddr_t madt_pa, srat_pa; 531109963Sjmallett int map_counts[MAXMEMDOM + 1] = { 0 }; 532109963Sjmallett 533109963Sjmallett /* Check ITS block in MADT */ 53442873Sluoqi madt_pa = acpi_find_table(ACPI_SIG_MADT); 53542873Sluoqi KASSERT(madt_pa != 0, ("no MADT!")); 536109963Sjmallett madt = acpi_map_table(madt_pa, ACPI_SIG_MADT); 53742873Sluoqi KASSERT(madt != NULL, ("can't map MADT!")); 53842873Sluoqi acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length, 539102231Strhodes madt_resolve_its_xref, NULL); 54042873Sluoqi acpi_unmap_table(madt); 5411558Srgrimes 542109963Sjmallett /* Get proximtiy if available */ 543109963Sjmallett srat_pa = acpi_find_table(ACPI_SIG_SRAT); 544109963Sjmallett if (srat_pa != 0) { 545109963Sjmallett srat = acpi_map_table(srat_pa, ACPI_SIG_SRAT); 546109963Sjmallett KASSERT(srat != NULL, ("can't map SRAT!")); 5471558Srgrimes acpi_walk_subtables(srat + 1, (char *)srat + srat->Header.Length, 5481558Srgrimes srat_resolve_its_pxm, map_counts); 5491558Srgrimes acpi_unmap_table(srat); 550207141Sjeff } 551207141Sjeff return (0); 552207141Sjeff} 553207141Sjeff 554207141Sjeff/* 555207141Sjeff * Find, parse, and save IO Remapping Table ("IORT"). 556227081Sed */ 557207141Sjeffstatic int 558207141Sjeffacpi_parse_iort(void *dummy __unused) 559207141Sjeff{ 560207141Sjeff ACPI_TABLE_IORT *iort; 561207141Sjeff ACPI_IORT_NODE *node_entry; 562207141Sjeff vm_paddr_t iort_pa; 563207141Sjeff u_int node_offset; 564207141Sjeff 565207141Sjeff iort_pa = acpi_find_table(ACPI_SIG_IORT); 566207141Sjeff if (iort_pa == 0) 567207141Sjeff return (ENXIO); 568207141Sjeff 569207141Sjeff iort = acpi_map_table(iort_pa, ACPI_SIG_IORT); 570207141Sjeff if (iort == NULL) { 571207141Sjeff printf("ACPI: Unable to map the IORT table!\n"); 572207141Sjeff return (ENXIO); 573207141Sjeff } 574207141Sjeff for (node_offset = iort->NodeOffset; 575207141Sjeff node_offset < iort->Header.Length; 576207141Sjeff node_offset += node_entry->Length) { 577207141Sjeff node_entry = ACPI_ADD_PTR(ACPI_IORT_NODE, iort, node_offset); 578207141Sjeff iort_add_nodes(node_entry, node_offset); 579207141Sjeff } 580207141Sjeff acpi_unmap_table(iort); 581207141Sjeff iort_post_process_mappings(); 582207141Sjeff iort_post_process_its(); 583207141Sjeff return (0); 584207141Sjeff} 585208241SjeffSYSINIT(acpi_parse_iort, SI_SUB_DRIVERS, SI_ORDER_FIRST, acpi_parse_iort, NULL); 586207141Sjeff 587207141Sjeff/* 588207141Sjeff * Provide ITS ID to PIC xref mapping. 589207141Sjeff */ 590207141Sjeffint 591207141Sjeffacpi_iort_its_lookup(u_int its_id, u_int *xref, int *pxm) 592207141Sjeff{ 593207141Sjeff struct iort_node *its_node; 594207141Sjeff struct iort_its_entry *its_entry; 595207141Sjeff int i; 596207141Sjeff 597207141Sjeff TAILQ_FOREACH(its_node, &its_groups, next) { 598207141Sjeff its_entry = its_node->entries.its; 599207141Sjeff for (i = 0; i < its_node->nentries; i++, its_entry++) { 600207141Sjeff if (its_entry->its_id == its_id) { 601207141Sjeff *xref = its_entry->xref; 602207141Sjeff *pxm = its_entry->pxm; 603207141Sjeff return (0); 604207141Sjeff } 605207141Sjeff } 606207141Sjeff } 607207141Sjeff return (ENOENT); 608207141Sjeff} 609207141Sjeff 610207141Sjeff/* 611207141Sjeff * Find mapping for a PCIe device given segment and device ID 612207141Sjeff * returns the XREF for MSI interrupt setup and the device ID to 613207141Sjeff * use for the interrupt setup 614207141Sjeff */ 615207141Sjeffint 616207141Sjeffacpi_iort_map_pci_msi(u_int seg, u_int rid, u_int *xref, u_int *devid) 617207141Sjeff{ 618207141Sjeff struct iort_node *node; 619207141Sjeff 620207141Sjeff node = iort_pci_rc_map(seg, rid, ACPI_IORT_NODE_ITS_GROUP, devid); 621207141Sjeff if (node == NULL) 622207141Sjeff return (ENOENT); 623207141Sjeff 624207141Sjeff /* This should be an ITS node */ 625207141Sjeff KASSERT(node->type == ACPI_IORT_NODE_ITS_GROUP, ("bad group")); 626207141Sjeff 627207141Sjeff /* return first node, we don't handle more than that now. */ 628207141Sjeff *xref = node->entries.its[0].xref; 629207141Sjeff return (0); 630207141Sjeff} 631207141Sjeff 632207141Sjeffint 633207141Sjeffacpi_iort_map_pci_smmuv3(u_int seg, u_int rid, u_int *xref, u_int *sid) 634207141Sjeff{ 635207141Sjeff ACPI_IORT_SMMU_V3 *smmu; 636207141Sjeff struct iort_node *node; 637207141Sjeff 638207141Sjeff node = iort_pci_rc_map(seg, rid, ACPI_IORT_NODE_SMMU_V3, sid); 639207141Sjeff if (node == NULL) 640207141Sjeff return (ENOENT); 641207141Sjeff 642207141Sjeff /* This should be an SMMU node. */ 643207141Sjeff KASSERT(node->type == ACPI_IORT_NODE_SMMU_V3, ("bad node")); 644207141Sjeff 645207141Sjeff smmu = (ACPI_IORT_SMMU_V3 *)&node->data.smmu_v3; 646207141Sjeff *xref = smmu->BaseAddress; 647207141Sjeff 648207141Sjeff return (0); 649207141Sjeff} 650207141Sjeff 651207141Sjeff/* 652207141Sjeff * Finds mapping for a named node given name and resource ID and returns the 653207141Sjeff * XREF for MSI interrupt setup and the device ID to use for the interrupt setup. 654207141Sjeff */ 655207141Sjeffint 656207141Sjeffacpi_iort_map_named_msi(const char *devname, u_int rid, u_int *xref, 657207141Sjeff u_int *devid) 658207141Sjeff{ 659207141Sjeff struct iort_node *node; 660207141Sjeff 661207141Sjeff node = iort_named_comp_map(devname, rid, ACPI_IORT_NODE_ITS_GROUP, 662207141Sjeff devid); 663207141Sjeff if (node == NULL) 664207141Sjeff return (ENOENT); 665207141Sjeff 666207141Sjeff /* This should be an ITS node */ 667207141Sjeff KASSERT(node->type == ACPI_IORT_NODE_ITS_GROUP, ("bad group")); 668207141Sjeff 669207141Sjeff /* Return first node, we don't handle more than that now. */ 670207141Sjeff *xref = node->entries.its[0].xref; 671207141Sjeff return (0); 672207141Sjeff} 673207141Sjeff 674207141Sjeffint 675207141Sjeffacpi_iort_map_named_smmuv3(const char *devname, u_int rid, u_int *xref, 676207141Sjeff u_int *devid) 677207141Sjeff{ 678207141Sjeff ACPI_IORT_SMMU_V3 *smmu; 679207141Sjeff struct iort_node *node; 680207141Sjeff 681207141Sjeff node = iort_named_comp_map(devname, rid, ACPI_IORT_NODE_SMMU_V3, devid); 682207141Sjeff if (node == NULL) 683207141Sjeff return (ENOENT); 684207141Sjeff 685207141Sjeff /* This should be an SMMU node. */ 686207141Sjeff KASSERT(node->type == ACPI_IORT_NODE_SMMU_V3, ("bad node")); 687207141Sjeff 688207141Sjeff smmu = (ACPI_IORT_SMMU_V3 *)&node->data.smmu_v3; 689207141Sjeff *xref = smmu->BaseAddress; 690207141Sjeff 691207141Sjeff return (0); 692218603Skib} 693218603Skib