xref: /aosp_15_r20/external/coreboot/src/soc/intel/xeon_sp/spr/ioat.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 #include <acpi/acpigen_pci.h>
3 #include <stdbool.h>
4 
5 #include <console/console.h>
6 #include <device/device.h>
7 
8 #include <defs_iio.h>
9 #include <hob_iiouds.h>
10 #include <intelblocks/acpi.h>
11 #include <intelblocks/vtd.h>
12 #include <soc/acpi.h>
13 #include <IioPcieConfigUpd.h>
14 
15 #include <soc/chip_common.h>
16 
17 /*
18  * Used for IIO stacks for accelerators and other functionality (IOAT).
19  * Those have only integrated PCI endpoints (no bridges) behind the host bridge.
20  */
21 
22 static struct device_operations ioat_domain_ops = {
23 	.read_resources = noop_read_resources,
24 	.set_resources = pci_domain_set_resources,
25 	.scan_bus = pci_host_bridge_scan_bus,
26 #if CONFIG(HAVE_ACPI_TABLES)
27 	.acpi_name        = soc_acpi_name,
28 	.write_acpi_tables = northbridge_write_acpi_tables,
29 	.acpi_fill_ssdt	   = pci_domain_fill_ssdt,
30 #endif
31 };
32 
create_ioat_domain(const union xeon_domain_path dp,struct bus * const upstream,const unsigned int bus_base,const unsigned int bus_limit,const resource_t mem32_base,const resource_t mem32_limit,const resource_t mem64_base,const resource_t mem64_limit,const char * prefix,const size_t pci_segment_group)33 static struct device *const create_ioat_domain(const union xeon_domain_path dp, struct bus *const upstream,
34 				const unsigned int bus_base, const unsigned int bus_limit,
35 				const resource_t mem32_base, const resource_t mem32_limit,
36 				const resource_t mem64_base, const resource_t mem64_limit,
37 				const char *prefix, const size_t pci_segment_group)
38 {
39 	union xeon_domain_path new_path = {
40 		.domain_path = dp.domain_path
41 	};
42 	new_path.bus = bus_base;
43 
44 	struct device_path path = {
45 		.type = DEVICE_PATH_DOMAIN,
46 		.domain = {
47 			.domain = new_path.domain_path,
48 		},
49 	};
50 	struct device *const domain = alloc_find_dev(upstream, &path);
51 	if (!domain)
52 		die("%s: out of memory.\n", __func__);
53 
54 	domain->ops = &ioat_domain_ops;
55 	iio_domain_set_acpi_name(domain, prefix);
56 
57 	struct bus *const bus = alloc_bus(domain);
58 	bus->secondary = bus_base;
59 	bus->subordinate = bus->secondary;
60 	bus->max_subordinate = bus_limit;
61 	bus->segment_group = pci_segment_group;
62 
63 	unsigned int index = 0;
64 
65 	if (mem32_base <= mem32_limit)
66 		domain_mem_window_from_to(domain, index++, mem32_base, mem32_limit + 1);
67 
68 	if (mem64_base <= mem64_limit)
69 		domain_mem_window_from_to(domain, index++, mem64_base, mem64_limit + 1);
70 
71 	return domain;
72 }
73 
create_ioat_domains(const union xeon_domain_path path,struct bus * const bus,const STACK_RES * const sr,const size_t pci_segment_group)74 void create_ioat_domains(const union xeon_domain_path path,
75 			struct bus *const bus,
76 			const STACK_RES *const sr,
77 			const size_t pci_segment_group)
78 {
79 	if (sr->BusLimit < sr->BusBase + HQM_BUS_OFFSET + HQM_RESERVED_BUS) {
80 		printk(BIOS_WARNING,
81 			"Ignoring IOAT domain with limited bus range.\n");
82 		return;
83 	}
84 
85 	if (sr->PciResourceMem64Limit - sr->PciResourceMem64Base + 1
86 	    < 2 * CPM_MMIO_SIZE + 2 * HQM_MMIO_SIZE) {
87 		printk(BIOS_WARNING,
88 		       "Ignoring IOAT domain with limited 64-bit MMIO window.\n");
89 		return;
90 	}
91 
92 	/* The FSP HOB doesn't provide accurate information about the
93 	   resource allocation. Hence use pre-defined offsets. Based
94 	   on ACPI code in create_dsdt_ioat_resource(), soc_acpi.c: */
95 	resource_t mem64_base, mem64_limit, bus_base, bus_limit;
96 
97 	/* CPM0 */
98 	mem64_base = sr->PciResourceMem64Base;
99 	mem64_limit = mem64_base + CPM_MMIO_SIZE - 1;
100 	bus_base = sr->BusBase + CPM_BUS_OFFSET;
101 	bus_limit = bus_base + CPM_RESERVED_BUS;
102 	create_ioat_domain(path, bus, bus_base, bus_limit, -1, 0, mem64_base, mem64_limit,
103 			   DOMAIN_TYPE_CPM0, pci_segment_group);
104 
105 	/* HQM0 */
106 	mem64_base = mem64_limit + 1;
107 	mem64_limit = mem64_base + HQM_MMIO_SIZE - 1;
108 	bus_base = sr->BusBase + HQM_BUS_OFFSET;
109 	bus_limit = bus_base + HQM_RESERVED_BUS;
110 	create_ioat_domain(path, bus, bus_base, bus_limit, -1, 0, mem64_base, mem64_limit,
111 			   DOMAIN_TYPE_HQM0, pci_segment_group);
112 
113 	/* CPM1 (optional) */
114 	mem64_base = mem64_limit + 1;
115 	mem64_limit = mem64_base + CPM_MMIO_SIZE - 1;
116 	bus_base = sr->BusBase + CPM1_BUS_OFFSET;
117 	bus_limit = bus_base + CPM_RESERVED_BUS;
118 	if (bus_limit <= sr->BusLimit)
119 		create_ioat_domain(path, bus, bus_base, bus_limit, -1, 0, mem64_base, mem64_limit,
120 				   DOMAIN_TYPE_CPM1, pci_segment_group);
121 
122 	/* HQM1 (optional) */
123 	mem64_base = mem64_limit + 1;
124 	mem64_limit = mem64_base + HQM_MMIO_SIZE - 1;
125 	bus_base = sr->BusBase + HQM1_BUS_OFFSET;
126 	bus_limit = bus_base + HQM_RESERVED_BUS;
127 	if (bus_limit <= sr->BusLimit)
128 		create_ioat_domain(path, bus, bus_base, bus_limit, -1, 0, mem64_base, mem64_limit,
129 				   DOMAIN_TYPE_HQM1, pci_segment_group);
130 
131 	/* DINO */
132 	mem64_base = mem64_limit + 1;
133 	mem64_limit = sr->PciResourceMem64Limit;
134 	bus_base = sr->BusBase;
135 	bus_limit = bus_base;
136 	struct device *const dev = create_ioat_domain(path, bus, bus_base, bus_limit,
137 				sr->PciResourceMem32Base, sr->PciResourceMem32Limit,
138 				mem64_base, mem64_limit, DOMAIN_TYPE_DINO, pci_segment_group);
139 
140 	/* Declare domain reserved MMIO */
141 	uint64_t reserved_mmio = sr->VtdBarAddress + vtd_probe_bar_size(pcidev_on_root(0, 0));
142 	if ((reserved_mmio >= sr->PciResourceMem32Base) &&
143 	    (reserved_mmio <= sr->PciResourceMem32Limit)) {
144 		int index = 0;
145 		for (struct resource *res = dev->resource_list; res; res = res->next)
146 			index++;
147 		mmio_range(dev, index, reserved_mmio,
148 			sr->PciResourceMem32Limit - reserved_mmio + 1);
149 	}
150 }
151