1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (C) 2018 Marvell International Ltd.
5 *
6 * Author: Jayachandran C Nair <jchandra@freebsd.org>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#include "opt_acpi.h"
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD$");
34
35#include <sys/param.h>
36#include <sys/bus.h>
37#include <sys/kernel.h>
38#include <sys/malloc.h>
39
40#include <machine/intr.h>
41
42#include <contrib/dev/acpica/include/acpi.h>
43#include <contrib/dev/acpica/include/accommon.h>
44#include <contrib/dev/acpica/include/actables.h>
45
46#include <dev/acpica/acpivar.h>
47
48/*
49 * Track next XREF available for ITS groups.
50 */
51static u_int acpi_its_xref = ACPI_MSI_XREF;
52
53/*
54 * Some types of IORT nodes have a set of mappings.  Each of them map
55 * a range of device IDs [base..end] from the current node to another
56 * node. The corresponding device IDs on destination node starts at
57 * outbase.
58 */
59struct iort_map_entry {
60	u_int			base;
61	u_int			end;
62	u_int			outbase;
63	u_int			flags;
64	u_int			out_node_offset;
65	struct iort_node	*out_node;
66};
67
68/*
69 * The ITS group node does not have any outgoing mappings. It has a
70 * of a list of GIC ITS blocks which can handle the device ID. We
71 * will store the PIC XREF used by the block and the blocks proximity
72 * data here, so that it can be retrieved together.
73 */
74struct iort_its_entry {
75	u_int			its_id;
76	u_int			xref;
77	int			pxm;
78};
79
80/*
81 * IORT node. Each node has some device specific data depending on the
82 * type of the node. The node can also have a set of mappings, OR in
83 * case of ITS group nodes a set of ITS entries.
84 * The nodes are kept in a TAILQ by type.
85 */
86struct iort_node {
87	TAILQ_ENTRY(iort_node)	next;		/* next entry with same type */
88	enum AcpiIortNodeType	type;		/* ACPI type */
89	u_int			node_offset;	/* offset in IORT - node ID */
90	u_int			nentries;	/* items in array below */
91	u_int			usecount;	/* for bookkeeping */
92	union {
93		ACPI_IORT_ROOT_COMPLEX	pci_rc;		/* PCI root complex */
94		ACPI_IORT_SMMU		smmu;
95		ACPI_IORT_SMMU_V3	smmu_v3;
96	} data;
97	union {
98		struct iort_map_entry	*mappings;	/* node mappings  */
99		struct iort_its_entry	*its;		/* ITS IDs array */
100	} entries;
101};
102
103/* Lists for each of the types. */
104static TAILQ_HEAD(, iort_node) pci_nodes = TAILQ_HEAD_INITIALIZER(pci_nodes);
105static TAILQ_HEAD(, iort_node) smmu_nodes = TAILQ_HEAD_INITIALIZER(smmu_nodes);
106static TAILQ_HEAD(, iort_node) its_groups = TAILQ_HEAD_INITIALIZER(its_groups);
107
108/*
109 * Lookup an ID in the mappings array. If successful, map the input ID
110 * to the output ID and return the output node found.
111 */
112static struct iort_node *
113iort_entry_lookup(struct iort_node *node, u_int id, u_int *outid)
114{
115	struct iort_map_entry *entry;
116	int i;
117
118	entry = node->entries.mappings;
119	for (i = 0; i < node->nentries; i++, entry++) {
120		if (entry->base <= id && id <= entry->end)
121			break;
122	}
123	if (i == node->nentries)
124		return (NULL);
125	if ((entry->flags & ACPI_IORT_ID_SINGLE_MAPPING) == 0)
126		*outid =  entry->outbase + (id - entry->base);
127	else
128		*outid = entry->outbase;
129	return (entry->out_node);
130}
131
132/*
133 * Map a PCI RID to a SMMU node or an ITS node, based on outtype.
134 */
135static struct iort_node *
136iort_pci_rc_map(u_int seg, u_int rid, u_int outtype, u_int *outid)
137{
138	struct iort_node *node, *out_node;
139	u_int nxtid;
140
141	out_node = NULL;
142	TAILQ_FOREACH(node, &pci_nodes, next) {
143		if (node->data.pci_rc.PciSegmentNumber != seg)
144			continue;
145		out_node = iort_entry_lookup(node, rid, &nxtid);
146		if (out_node != NULL)
147			break;
148	}
149
150	/* Could not find a PCI RC node with segment and device ID. */
151	if (out_node == NULL)
152		return (NULL);
153
154	/* Node can be SMMU or ITS. If SMMU, we need another lookup. */
155	if (outtype == ACPI_IORT_NODE_ITS_GROUP &&
156	    (out_node->type == ACPI_IORT_NODE_SMMU_V3 ||
157	    out_node->type == ACPI_IORT_NODE_SMMU)) {
158		out_node = iort_entry_lookup(out_node, nxtid, &nxtid);
159		if (out_node == NULL)
160			return (NULL);
161	}
162
163	KASSERT(out_node->type == outtype, ("mapping fail"));
164	*outid = nxtid;
165	return (out_node);
166}
167
168#ifdef notyet
169/*
170 * Not implemented, map a PCIe device to the SMMU it is associated with.
171 */
172int
173acpi_iort_map_smmu(u_int seg, u_int devid, void **smmu, u_int *sid)
174{
175	/* XXX: convert oref to SMMU device */
176	return (ENXIO);
177}
178#endif
179
180/*
181 * Allocate memory for a node, initialize and copy mappings. 'start'
182 * argument provides the table start used to calculate the node offset.
183 */
184static void
185iort_copy_data(struct iort_node *node, ACPI_IORT_NODE *node_entry)
186{
187	ACPI_IORT_ID_MAPPING *map_entry;
188	struct iort_map_entry *mapping;
189	int i;
190
191	map_entry = ACPI_ADD_PTR(ACPI_IORT_ID_MAPPING, node_entry,
192	    node_entry->MappingOffset);
193	node->nentries = node_entry->MappingCount;
194	node->usecount = 0;
195	mapping = malloc(sizeof(*mapping) * node->nentries, M_DEVBUF,
196	    M_WAITOK | M_ZERO);
197	node->entries.mappings = mapping;
198	for (i = 0; i < node->nentries; i++, mapping++, map_entry++) {
199		mapping->base = map_entry->InputBase;
200		mapping->end = map_entry->InputBase + map_entry->IdCount - 1;
201		mapping->outbase = map_entry->OutputBase;
202		mapping->out_node_offset = map_entry->OutputReference;
203		mapping->flags = map_entry->Flags;
204		mapping->out_node = NULL;
205	}
206}
207
208/*
209 * Allocate and copy an ITS group.
210 */
211static void
212iort_copy_its(struct iort_node *node, ACPI_IORT_NODE *node_entry)
213{
214	struct iort_its_entry *its;
215	ACPI_IORT_ITS_GROUP *itsg_entry;
216	UINT32 *id;
217	int i;
218
219	itsg_entry = (ACPI_IORT_ITS_GROUP *)node_entry->NodeData;
220	node->nentries = itsg_entry->ItsCount;
221	node->usecount = 0;
222	its = malloc(sizeof(*its) * node->nentries, M_DEVBUF, M_WAITOK | M_ZERO);
223	node->entries.its = its;
224	id = &itsg_entry->Identifiers[0];
225	for (i = 0; i < node->nentries; i++, its++, id++) {
226		its->its_id = *id;
227		its->pxm = -1;
228		its->xref = 0;
229	}
230}
231
232/*
233 * Walk the IORT table and add nodes to corresponding list.
234 */
235static void
236iort_add_nodes(ACPI_IORT_NODE *node_entry, u_int node_offset)
237{
238	ACPI_IORT_ROOT_COMPLEX *pci_rc;
239	ACPI_IORT_SMMU *smmu;
240	ACPI_IORT_SMMU_V3 *smmu_v3;
241	struct iort_node *node;
242
243	node = malloc(sizeof(*node), M_DEVBUF, M_WAITOK | M_ZERO);
244	node->type =  node_entry->Type;
245	node->node_offset = node_offset;
246
247	/* copy nodes depending on type */
248	switch(node_entry->Type) {
249	case ACPI_IORT_NODE_PCI_ROOT_COMPLEX:
250		pci_rc = (ACPI_IORT_ROOT_COMPLEX *)node_entry->NodeData;
251		memcpy(&node->data.pci_rc, pci_rc, sizeof(*pci_rc));
252		iort_copy_data(node, node_entry);
253		TAILQ_INSERT_TAIL(&pci_nodes, node, next);
254		break;
255	case ACPI_IORT_NODE_SMMU:
256		smmu = (ACPI_IORT_SMMU *)node_entry->NodeData;
257		memcpy(&node->data.smmu, smmu, sizeof(*smmu));
258		iort_copy_data(node, node_entry);
259		TAILQ_INSERT_TAIL(&smmu_nodes, node, next);
260		break;
261	case ACPI_IORT_NODE_SMMU_V3:
262		smmu_v3 = (ACPI_IORT_SMMU_V3 *)node_entry->NodeData;
263		memcpy(&node->data.smmu_v3, smmu_v3, sizeof(*smmu_v3));
264		iort_copy_data(node, node_entry);
265		TAILQ_INSERT_TAIL(&smmu_nodes, node, next);
266		break;
267	case ACPI_IORT_NODE_ITS_GROUP:
268		iort_copy_its(node, node_entry);
269		TAILQ_INSERT_TAIL(&its_groups, node, next);
270		break;
271	default:
272		printf("ACPI: IORT: Dropping unhandled type %u\n",
273		    node_entry->Type);
274		free(node, M_DEVBUF);
275		break;
276	}
277}
278
279/*
280 * For the mapping entry given, walk thru all the possible destination
281 * nodes and resolve the output reference.
282 */
283static void
284iort_resolve_node(struct iort_map_entry *entry, int check_smmu)
285{
286	struct iort_node *node, *np;
287
288	node = NULL;
289	if (check_smmu) {
290		TAILQ_FOREACH(np, &smmu_nodes, next) {
291			if (entry->out_node_offset == np->node_offset) {
292				node = np;
293				break;
294			}
295		}
296	}
297	if (node == NULL) {
298		TAILQ_FOREACH(np, &its_groups, next) {
299			if (entry->out_node_offset == np->node_offset) {
300				node = np;
301				break;
302			}
303		}
304	}
305	if (node != NULL) {
306		node->usecount++;
307		entry->out_node = node;
308	} else {
309		printf("ACPI: IORT: Firmware Bug: no mapping for node %u\n",
310		    entry->out_node_offset);
311	}
312}
313
314/*
315 * Resolve all output node references to node pointers.
316 */
317static void
318iort_post_process_mappings(void)
319{
320	struct iort_node *node;
321	int i;
322
323	TAILQ_FOREACH(node, &pci_nodes, next)
324		for (i = 0; i < node->nentries; i++)
325			iort_resolve_node(&node->entries.mappings[i], TRUE);
326	TAILQ_FOREACH(node, &smmu_nodes, next)
327		for (i = 0; i < node->nentries; i++)
328			iort_resolve_node(&node->entries.mappings[i], FALSE);
329	/* TODO: named nodes */
330}
331
332/*
333 * Walk MADT table, assign PIC xrefs to all ITS entries.
334 */
335static void
336madt_resolve_its_xref(ACPI_SUBTABLE_HEADER *entry, void *arg)
337{
338	ACPI_MADT_GENERIC_TRANSLATOR *gict;
339	struct iort_node *its_node;
340	struct iort_its_entry *its_entry;
341	u_int xref;
342	int i, matches;
343
344        if (entry->Type != ACPI_MADT_TYPE_GENERIC_TRANSLATOR)
345		return;
346
347	gict = (ACPI_MADT_GENERIC_TRANSLATOR *)entry;
348	matches = 0;
349	xref = acpi_its_xref++;
350	TAILQ_FOREACH(its_node, &its_groups, next) {
351		its_entry = its_node->entries.its;
352		for (i = 0; i < its_node->nentries; i++, its_entry++) {
353			if (its_entry->its_id == gict->TranslationId) {
354				its_entry->xref = xref;
355				matches++;
356			}
357		}
358	}
359	if (matches == 0)
360		printf("ACPI: IORT: Unused ITS block, ID %u\n",
361		    gict->TranslationId);
362}
363
364/*
365 * Walk SRAT, assign proximity to all ITS entries.
366 */
367static void
368srat_resolve_its_pxm(ACPI_SUBTABLE_HEADER *entry, void *arg)
369{
370	ACPI_SRAT_GIC_ITS_AFFINITY *gicits;
371	struct iort_node *its_node;
372	struct iort_its_entry *its_entry;
373	int *map_counts;
374	int i, matches, dom;
375
376	if (entry->Type != ACPI_SRAT_TYPE_GIC_ITS_AFFINITY)
377		return;
378
379	matches = 0;
380	map_counts = arg;
381	gicits = (ACPI_SRAT_GIC_ITS_AFFINITY *)entry;
382	dom = acpi_map_pxm_to_vm_domainid(gicits->ProximityDomain);
383
384	/*
385	 * Catch firmware and config errors. map_counts keeps a
386	 * count of ProximityDomain values mapping to a domain ID
387	 */
388#if MAXMEMDOM > 1
389	if (dom == -1)
390		printf("Firmware Error: Proximity Domain %d could not be"
391		    " mapped for GIC ITS ID %d!\n",
392		    gicits->ProximityDomain, gicits->ItsId);
393#endif
394	/* use dom + 1 as index to handle the case where dom == -1 */
395	i = ++map_counts[dom + 1];
396	if (i > 1) {
397#ifdef NUMA
398		if (dom != -1)
399			printf("ERROR: Multiple Proximity Domains map to the"
400			    " same NUMA domain %d!\n", dom);
401#else
402		printf("WARNING: multiple Proximity Domains in SRAT but NUMA"
403		    " NOT enabled!\n");
404#endif
405	}
406	TAILQ_FOREACH(its_node, &its_groups, next) {
407		its_entry = its_node->entries.its;
408		for (i = 0; i < its_node->nentries; i++, its_entry++) {
409			if (its_entry->its_id == gicits->ItsId) {
410				its_entry->pxm = dom;
411				matches++;
412			}
413		}
414	}
415	if (matches == 0)
416		printf("ACPI: IORT: ITS block %u in SRAT not found in IORT!\n",
417		    gicits->ItsId);
418}
419
420/*
421 * Cross check the ITS Id with MADT and (if available) SRAT.
422 */
423static int
424iort_post_process_its(void)
425{
426	ACPI_TABLE_MADT *madt;
427	ACPI_TABLE_SRAT *srat;
428	vm_paddr_t madt_pa, srat_pa;
429	int map_counts[MAXMEMDOM + 1] = { 0 };
430
431	/* Check ITS block in MADT */
432	madt_pa = acpi_find_table(ACPI_SIG_MADT);
433	KASSERT(madt_pa != 0, ("no MADT!"));
434	madt = acpi_map_table(madt_pa, ACPI_SIG_MADT);
435	KASSERT(madt != NULL, ("can't map MADT!"));
436	acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
437	    madt_resolve_its_xref, NULL);
438	acpi_unmap_table(madt);
439
440	/* Get proximtiy if available */
441	srat_pa = acpi_find_table(ACPI_SIG_SRAT);
442	if (srat_pa != 0) {
443		srat = acpi_map_table(srat_pa, ACPI_SIG_SRAT);
444		KASSERT(srat != NULL, ("can't map SRAT!"));
445		acpi_walk_subtables(srat + 1, (char *)srat + srat->Header.Length,
446		    srat_resolve_its_pxm, map_counts);
447		acpi_unmap_table(srat);
448	}
449	return (0);
450}
451
452/*
453 * Find, parse, and save IO Remapping Table ("IORT").
454 */
455static int
456acpi_parse_iort(void *dummy __unused)
457{
458	ACPI_TABLE_IORT *iort;
459	ACPI_IORT_NODE *node_entry;
460	vm_paddr_t iort_pa;
461	u_int node_offset;
462
463	iort_pa = acpi_find_table(ACPI_SIG_IORT);
464	if (iort_pa == 0)
465		return (ENXIO);
466
467	iort = acpi_map_table(iort_pa, ACPI_SIG_IORT);
468	if (iort == NULL) {
469		printf("ACPI: Unable to map the IORT table!\n");
470		return (ENXIO);
471	}
472	for (node_offset = iort->NodeOffset;
473	    node_offset < iort->Header.Length;
474	    node_offset += node_entry->Length) {
475		node_entry = ACPI_ADD_PTR(ACPI_IORT_NODE, iort, node_offset);
476		iort_add_nodes(node_entry, node_offset);
477	}
478	acpi_unmap_table(iort);
479	iort_post_process_mappings();
480	iort_post_process_its();
481	return (0);
482}
483SYSINIT(acpi_parse_iort, SI_SUB_DRIVERS, SI_ORDER_FIRST, acpi_parse_iort, NULL);
484
485/*
486 * Provide ITS ID to PIC xref mapping.
487 */
488int
489acpi_iort_its_lookup(u_int its_id, u_int *xref, int *pxm)
490{
491	struct iort_node *its_node;
492	struct iort_its_entry *its_entry;
493	int i;
494
495	TAILQ_FOREACH(its_node, &its_groups, next) {
496		its_entry = its_node->entries.its;
497		for  (i = 0; i < its_node->nentries; i++, its_entry++) {
498			if (its_entry->its_id == its_id) {
499				*xref = its_entry->xref;
500				*pxm = its_entry->pxm;
501				return (0);
502			}
503		}
504	}
505	return (ENOENT);
506}
507
508/*
509 * Find mapping for a PCIe device given segment and device ID
510 * returns the XREF for MSI interrupt setup and the device ID to
511 * use for the interrupt setup
512 */
513int
514acpi_iort_map_pci_msi(u_int seg, u_int rid, u_int *xref, u_int *devid)
515{
516	struct iort_node *node;
517
518	node = iort_pci_rc_map(seg, rid, ACPI_IORT_NODE_ITS_GROUP, devid);
519	if (node == NULL)
520		return (ENOENT);
521
522	/* This should be an ITS node */
523	KASSERT(node->type == ACPI_IORT_NODE_ITS_GROUP, ("bad group"));
524
525	/* return first node, we don't handle more than that now. */
526	*xref = node->entries.its[0].xref;
527	return (0);
528}
529