blob: afe79fe8ca9eafa5050b268996bfcd55968660a7 [file] [log] [blame]
Felix Held407bd582023-04-24 17:58:24 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2
Felix Held7a5dd782023-04-28 22:47:33 +02003#include <acpi/acpigen.h>
Felix Held407bd582023-04-24 17:58:24 +02004#include <amdblocks/data_fabric.h>
Felix Held32169722023-07-14 19:41:06 +02005#include <amdblocks/root_complex.h>
Felix Held407bd582023-04-24 17:58:24 +02006#include <arch/ioapic.h>
Felix Held7a5dd782023-04-28 22:47:33 +02007#include <arch/vga.h>
Felix Held407bd582023-04-24 17:58:24 +02008#include <console/console.h>
9#include <cpu/amd/mtrr.h>
Felix Held89ca4782023-09-12 15:01:02 +020010#include <cpu/cpu.h>
Felix Held407bd582023-04-24 17:58:24 +020011#include <device/device.h>
Felix Held3b5b66d2024-01-11 22:26:18 +010012#include <device/pci.h>
Felix Held407bd582023-04-24 17:58:24 +020013#include <device/pci_ops.h>
14#include <types.h>
15
16void amd_pci_domain_scan_bus(struct device *domain)
17{
Felix Held6c00a6a2023-12-06 23:40:42 +010018 uint8_t segment_group, bus, limit;
Felix Held407bd582023-04-24 17:58:24 +020019
Felix Held6c00a6a2023-12-06 23:40:42 +010020 if (data_fabric_get_pci_bus_numbers(domain, &segment_group, &bus, &limit) != CB_SUCCESS) {
Felix Heldea831392023-08-08 02:55:09 +020021 printk(BIOS_ERR, "No PCI bus numbers decoded to PCI root.\n");
22 return;
23 }
24
Felix Held3b5b66d2024-01-11 22:26:18 +010025 if (segment_group >= PCI_SEGMENT_GROUP_COUNT) {
26 printk(BIOS_ERR, "Skipping domain %u due to too large segment group %u.\n",
27 domain->path.domain.domain, segment_group);
Felix Held6c00a6a2023-12-06 23:40:42 +010028 return;
29 }
30
Felix Held3b5b66d2024-01-11 22:26:18 +010031 /* TODO: Check if bus >= PCI_BUSES_PER_SEGMENT_GROUP and return in that case */
Felix Heldea831392023-08-08 02:55:09 +020032
Felix Held3b5b66d2024-01-11 22:26:18 +010033 /* Make sure to not report more than PCI_BUSES_PER_SEGMENT_GROUP PCI buses */
34 limit = MIN(limit, PCI_BUSES_PER_SEGMENT_GROUP - 1);
Felix Held407bd582023-04-24 17:58:24 +020035
36 /* Set bus first number of PCI root */
Arthur Heymans7fcd4d52023-08-24 15:12:19 +020037 domain->downstream->secondary = bus;
Arthur Heymans0b0113f2023-08-31 17:09:28 +020038 /* subordinate needs to be the same as secondary before pci_host_bridge_scan_bus call. */
Arthur Heymans7fcd4d52023-08-24 15:12:19 +020039 domain->downstream->subordinate = bus;
Felix Held9dcdec52023-08-08 21:38:43 +020040 /* Tell allocator about maximum PCI bus number in domain */
Arthur Heymans7fcd4d52023-08-24 15:12:19 +020041 domain->downstream->max_subordinate = limit;
42 domain->downstream->segment_group = segment_group;
Felix Held407bd582023-04-24 17:58:24 +020043
Arthur Heymans0b0113f2023-08-31 17:09:28 +020044 pci_host_bridge_scan_bus(domain);
Felix Held407bd582023-04-24 17:58:24 +020045}
46
Felix Held407bd582023-04-24 17:58:24 +020047static void print_df_mmio_outside_of_cpu_mmio_error(unsigned int reg)
48{
49 printk(BIOS_WARNING, "DF MMIO register %u outside of CPU MMIO region.\n", reg);
50}
51
52static bool is_mmio_region_valid(unsigned int reg, resource_t mmio_base, resource_t mmio_limit)
53{
54 if (mmio_base > mmio_limit) {
55 printk(BIOS_WARNING, "DF MMIO register %u's base is above its limit.\n", reg);
56 return false;
57 }
58 if (mmio_base >= 4ULL * GiB) {
59 /* MMIO region above 4GB needs to be above TOP_MEM2 MSR value */
60 if (mmio_base < get_top_of_mem_above_4gb()) {
61 print_df_mmio_outside_of_cpu_mmio_error(reg);
62 return false;
63 }
64 } else {
65 /* MMIO region below 4GB needs to be above TOP_MEM MSR value */
66 if (mmio_base < get_top_of_mem_below_4gb()) {
67 print_df_mmio_outside_of_cpu_mmio_error(reg);
68 return false;
69 }
70 /* MMIO region below 4GB mustn't cross the 4GB boundary. */
71 if (mmio_limit >= 4ULL * GiB) {
72 printk(BIOS_WARNING, "DF MMIO register %u crosses 4GB boundary.\n",
73 reg);
74 return false;
75 }
76 }
77
78 return true;
79}
80
Felix Helde4594f12024-01-30 22:04:34 +010081static void report_data_fabric_mmio(struct device *domain, unsigned long idx,
Felix Held407bd582023-04-24 17:58:24 +020082 resource_t mmio_base, resource_t mmio_limit)
83{
84 struct resource *res;
85 res = new_resource(domain, idx);
86 res->base = mmio_base;
87 res->limit = mmio_limit;
88 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED;
89}
90
91/* Tell the resource allocator about the usable MMIO ranges configured in the data fabric */
Felix Helde4594f12024-01-30 22:04:34 +010092static void add_data_fabric_mmio_regions(struct device *domain, unsigned long *idx)
Felix Held407bd582023-04-24 17:58:24 +020093{
Felix Held9cbdc8f2023-08-11 22:30:06 +020094 const signed int iohc_dest_fabric_id = get_iohc_fabric_id(domain);
Felix Held407bd582023-04-24 17:58:24 +020095 union df_mmio_control ctrl;
96 resource_t mmio_base;
97 resource_t mmio_limit;
98
99 /* The last 12GB of the usable address space are reserved and can't be used for MMIO */
100 const resource_t reserved_upper_mmio_base =
Felix Held89ca4782023-09-12 15:01:02 +0200101 (1ULL << cpu_phys_address_size()) - DF_RESERVED_TOP_12GB_MMIO_SIZE;
Felix Held407bd582023-04-24 17:58:24 +0200102
103 for (unsigned int i = 0; i < DF_MMIO_REG_SET_COUNT; i++) {
Felix Held18a3c232023-08-03 00:10:03 +0200104 ctrl.raw = data_fabric_broadcast_read32(DF_MMIO_CONTROL(i));
Felix Held407bd582023-04-24 17:58:24 +0200105
106 /* Relevant MMIO regions need to have both reads and writes enabled */
107 if (!ctrl.we || !ctrl.re)
108 continue;
109
110 /* Non-posted region contains fixed FCH MMIO devices */
111 if (ctrl.np)
112 continue;
113
Felix Held55822d92023-08-08 21:38:07 +0200114 /* Only look at MMIO regions that are decoded to the right PCI root */
Felix Held9cbdc8f2023-08-11 22:30:06 +0200115 if (ctrl.dst_fabric_id != iohc_dest_fabric_id)
Felix Held55822d92023-08-08 21:38:07 +0200116 continue;
Felix Held407bd582023-04-24 17:58:24 +0200117
118 data_fabric_get_mmio_base_size(i, &mmio_base, &mmio_limit);
119
120 if (!is_mmio_region_valid(i, mmio_base, mmio_limit))
121 continue;
122
123 /* Make sure to not report a region overlapping with the fixed MMIO resources
124 below 4GB or the reserved MMIO range in the last 12GB of the addressable
125 address range. The code assumes that the fixed MMIO resources below 4GB
126 are between IO_APIC_ADDR and the 4GB boundary. */
127 if (mmio_base < 4ULL * GiB) {
128 if (mmio_base >= IO_APIC_ADDR)
129 continue;
130 if (mmio_limit >= IO_APIC_ADDR)
131 mmio_limit = IO_APIC_ADDR - 1;
132 } else {
133 if (mmio_base >= reserved_upper_mmio_base)
134 continue;
135 if (mmio_limit >= reserved_upper_mmio_base)
136 mmio_limit = reserved_upper_mmio_base - 1;
137 }
138
139 report_data_fabric_mmio(domain, (*idx)++, mmio_base, mmio_limit);
140 }
141}
142
Felix Helde4594f12024-01-30 22:04:34 +0100143static void report_data_fabric_io(struct device *domain, unsigned long idx,
Felix Held2dfd48b2023-08-04 19:22:54 +0200144 resource_t io_base, resource_t io_limit)
145{
146 struct resource *res;
147 res = new_resource(domain, idx);
148 res->base = io_base;
149 res->limit = io_limit;
150 res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED;
151}
152
Felix Held407bd582023-04-24 17:58:24 +0200153/* Tell the resource allocator about the usable I/O space */
Felix Helde4594f12024-01-30 22:04:34 +0100154static void add_data_fabric_io_regions(struct device *domain, unsigned long *idx)
Felix Held407bd582023-04-24 17:58:24 +0200155{
Felix Held9cbdc8f2023-08-11 22:30:06 +0200156 const signed int iohc_dest_fabric_id = get_iohc_fabric_id(domain);
Felix Held4eac0d42023-08-04 19:40:02 +0200157 union df_io_base base_reg;
158 union df_io_limit limit_reg;
159 resource_t io_base;
160 resource_t io_limit;
Felix Held407bd582023-04-24 17:58:24 +0200161
Felix Held4eac0d42023-08-04 19:40:02 +0200162 for (unsigned int i = 0; i < DF_IO_REG_COUNT; i++) {
163 base_reg.raw = data_fabric_broadcast_read32(DF_IO_BASE(i));
164
165 /* Relevant IO regions need to have both reads and writes enabled */
166 if (!base_reg.we || !base_reg.re)
167 continue;
168
169 limit_reg.raw = data_fabric_broadcast_read32(DF_IO_LIMIT(i));
170
Felix Held55822d92023-08-08 21:38:07 +0200171 /* Only look at IO regions that are decoded to the right PCI root */
Felix Held9cbdc8f2023-08-11 22:30:06 +0200172 if (limit_reg.dst_fabric_id != iohc_dest_fabric_id)
Felix Held55822d92023-08-08 21:38:07 +0200173 continue;
Felix Held4eac0d42023-08-04 19:40:02 +0200174
175 io_base = base_reg.io_base << DF_IO_ADDR_SHIFT;
176 io_limit = ((limit_reg.io_limit + 1) << DF_IO_ADDR_SHIFT) - 1;
177
178 /* Beware that the lower 25 bits of io_base and io_limit can be non-zero
179 despite there only being 16 bits worth of IO port address space. */
180 if (io_base > 0xffff) {
181 printk(BIOS_WARNING, "DF IO base register %d value outside of valid "
182 "IO port address range.\n", i);
183 continue;
184 }
185 /* If only the IO limit is outside of the valid 16 bit IO port range, report
186 the limit as 0xffff, so that the resource allcator won't put IO BARs outside
187 of the 16 bit IO port address range. */
188 io_limit = MIN(io_limit, 0xffff);
189
190 report_data_fabric_io(domain, (*idx)++, io_base, io_limit);
191 }
Felix Held407bd582023-04-24 17:58:24 +0200192}
193
Felix Helddde265f2024-01-30 15:40:53 +0100194static void add_pci_cfg_resources(struct device *domain, unsigned long *idx)
195{
196 fixed_io_range_reserved(domain, (*idx)++, PCI_IO_CONFIG_INDEX, PCI_IO_CONFIG_PORT_COUNT);
197 mmconf_resource(domain, (*idx)++);
198}
199
Felix Held407bd582023-04-24 17:58:24 +0200200void amd_pci_domain_read_resources(struct device *domain)
201{
Felix Helde4594f12024-01-30 22:04:34 +0100202 unsigned long idx = 0;
Felix Held407bd582023-04-24 17:58:24 +0200203
Felix Held3f3f93b2023-08-04 22:14:40 +0200204 add_data_fabric_io_regions(domain, &idx);
Felix Held407bd582023-04-24 17:58:24 +0200205
206 add_data_fabric_mmio_regions(domain, &idx);
Felix Held32169722023-07-14 19:41:06 +0200207
208 read_non_pci_resources(domain, &idx);
Felix Held30f36c32024-01-30 15:15:31 +0100209
210 /* Only add the SoC's DRAM memory map and fixed resources once */
211 if (domain->path.domain.domain == 0) {
Felix Helddde265f2024-01-30 15:40:53 +0100212 add_pci_cfg_resources(domain, &idx);
213
Felix Held30f36c32024-01-30 15:15:31 +0100214 read_soc_memmap_resources(domain, &idx);
215 }
Felix Held407bd582023-04-24 17:58:24 +0200216}
Felix Held7a5dd782023-04-28 22:47:33 +0200217
218static void write_ssdt_domain_io_producer_range_helper(const char *domain_name,
219 resource_t base, resource_t limit)
220{
221 printk(BIOS_DEBUG, "%s _CRS: adding IO range [%llx-%llx]\n", domain_name, base, limit);
222 acpigen_resource_producer_io(base, limit);
223}
224
225static void write_ssdt_domain_io_producer_range(const char *domain_name,
226 resource_t base, resource_t limit)
227{
228 /*
229 * Split the IO region at the PCI config IO ports so that the IO resource producer
230 * won't cover the same IO ports that the IO resource consumer for the PCI config IO
231 * ports in the same ACPI device already covers.
232 */
233 if (base < PCI_IO_CONFIG_INDEX) {
234 write_ssdt_domain_io_producer_range_helper(domain_name,
235 base,
236 MIN(limit, PCI_IO_CONFIG_INDEX - 1));
237 }
238 if (limit > PCI_IO_CONFIG_LAST_PORT) {
239 write_ssdt_domain_io_producer_range_helper(domain_name,
240 MAX(base, PCI_IO_CONFIG_LAST_PORT + 1),
241 limit);
242 }
243}
244
245static void write_ssdt_domain_mmio_producer_range(const char *domain_name,
246 resource_t base, resource_t limit)
247{
248 printk(BIOS_DEBUG, "%s _CRS: adding MMIO range [%llx-%llx]\n",
249 domain_name, base, limit);
250 acpigen_resource_producer_mmio(base, limit,
251 MEM_RSRC_FLAG_MEM_READ_WRITE | MEM_RSRC_FLAG_MEM_ATTR_NON_CACHE);
252}
253
254void amd_pci_domain_fill_ssdt(const struct device *domain)
255{
256 const char *acpi_scope = acpi_device_path(domain);
257 printk(BIOS_DEBUG, "%s ACPI scope: '%s'\n", __func__, acpi_scope);
258 acpigen_write_scope(acpi_device_path(domain));
259
260 acpigen_write_name("_CRS");
261 acpigen_write_resourcetemplate_header();
262
263 /* PCI bus number range in domain */
Felix Held3b5b66d2024-01-11 22:26:18 +0100264 printk(BIOS_DEBUG, "%s _CRS: adding busses [%x-%x] in segment group %x\n",
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200265 acpi_device_name(domain), domain->downstream->secondary,
266 domain->downstream->max_subordinate, domain->downstream->segment_group);
267 acpigen_resource_producer_bus_number(domain->downstream->secondary,
268 domain->downstream->max_subordinate);
Felix Held7a5dd782023-04-28 22:47:33 +0200269
Felix Held5881f8a2024-01-17 22:00:13 +0100270 if (domain->path.domain.domain == 0) {
Felix Held7a5dd782023-04-28 22:47:33 +0200271 /* ACPI 6.4.2.5 I/O Port Descriptor */
272 acpigen_write_io16(PCI_IO_CONFIG_INDEX, PCI_IO_CONFIG_LAST_PORT, 1,
273 PCI_IO_CONFIG_PORT_COUNT, 1);
274 }
275
276 struct resource *res;
277 for (res = domain->resource_list; res != NULL; res = res->next) {
278 if (!(res->flags & IORESOURCE_ASSIGNED))
Felix Helda239cf42023-07-29 01:45:31 +0200279 continue;
Felix Held0df754b2023-07-29 01:49:15 +0200280 /* Don't add MMIO producer ranges for reserved MMIO regions from non-PCI
281 devices */
282 if ((res->flags & IORESOURCE_RESERVE))
283 continue;
Felix Heldbf769982024-02-07 21:17:46 +0100284 /* Don't add MMIO producer ranges for DRAM regions */
285 if (res->flags & IORESOURCE_STORED)
286 continue;
Felix Held7a5dd782023-04-28 22:47:33 +0200287 switch (res->flags & IORESOURCE_TYPE_MASK) {
288 case IORESOURCE_IO:
289 write_ssdt_domain_io_producer_range(acpi_device_name(domain),
290 res->base, res->limit);
291 break;
292 case IORESOURCE_MEM:
293 write_ssdt_domain_mmio_producer_range(acpi_device_name(domain),
294 res->base, res->limit);
295 break;
296 default:
297 break;
298 }
299 }
300
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200301 if (domain->downstream->bridge_ctrl & PCI_BRIDGE_CTL_VGA) {
Felix Held7a5dd782023-04-28 22:47:33 +0200302 printk(BIOS_DEBUG, "%s _CRS: adding VGA resource\n", acpi_device_name(domain));
303 acpigen_resource_producer_mmio(VGA_MMIO_BASE, VGA_MMIO_LIMIT,
304 MEM_RSRC_FLAG_MEM_READ_WRITE | MEM_RSRC_FLAG_MEM_ATTR_CACHE);
305 }
306
307 acpigen_write_resourcetemplate_footer();
Felix Helde4b65cc2023-05-05 20:46:11 +0200308
Arthur Heymans7fcd4d52023-08-24 15:12:19 +0200309 acpigen_write_SEG(domain->downstream->segment_group);
310 acpigen_write_BBN(domain->downstream->secondary);
Felix Held7a5dd782023-04-28 22:47:33 +0200311 /* Scope */
312 acpigen_pop_len();
313}