blob: aec1596fc11067b73f1002cfd0d1345cc3d76460 [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/cpu.h>
5#include <amdblocks/data_fabric.h>
6#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>
10#include <device/device.h>
11#include <device/pci_ops.h>
12#include <types.h>
13
14void amd_pci_domain_scan_bus(struct device *domain)
15{
16 uint8_t bus, limit;
17
18 /* TODO: Systems with more than one PCI root need to read the data fabric registers to
19 see which PCI bus numbers get decoded to which PCI root. */
20 bus = 0;
21 limit = CONFIG_ECAM_MMCONF_BUS_NUMBER - 1;
22
23 /* Set bus first number of PCI root */
24 domain->link_list->secondary = bus;
25 /* subordinate needs to be the same as secondary before pci_domain_scan_bus call. */
26 domain->link_list->subordinate = bus;
27
28 pci_domain_scan_bus(domain);
29
30 /* pci_domain_scan_bus will modify subordinate, so change it back to the maximum
31 bus number decoded to this PCI root for the acpigen_resource_producer_bus_number
32 call to write the correct ACPI code. */
33 domain->link_list->subordinate = limit;
34}
35
36/* Read the registers and return normalized values */
37static void data_fabric_get_mmio_base_size(unsigned int reg,
38 resource_t *mmio_base, resource_t *mmio_limit)
39{
40 const uint32_t base_reg = data_fabric_broadcast_read32(0, DF_MMIO_BASE(reg));
41 const uint32_t limit_reg = data_fabric_broadcast_read32(0, DF_MMIO_LIMIT(reg));
42 /* The raw register values are bits 47..16 of the actual address */
43 *mmio_base = (resource_t)base_reg << D18F0_MMIO_SHIFT;
44 *mmio_limit = (((resource_t)limit_reg + 1) << D18F0_MMIO_SHIFT) - 1;
45}
46
47static 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
81static void report_data_fabric_mmio(struct device *domain, unsigned int idx,
82 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 */
92static void add_data_fabric_mmio_regions(struct device *domain, unsigned int *idx)
93{
94 union df_mmio_control ctrl;
95 resource_t mmio_base;
96 resource_t mmio_limit;
97
98 /* The last 12GB of the usable address space are reserved and can't be used for MMIO */
99 const resource_t reserved_upper_mmio_base =
100 (1ULL << get_usable_physical_address_bits()) - DF_RESERVED_TOP_12GB_MMIO_SIZE;
101
102 for (unsigned int i = 0; i < DF_MMIO_REG_SET_COUNT; i++) {
103 ctrl.raw = data_fabric_broadcast_read32(0, DF_MMIO_CONTROL(i));
104
105 /* Relevant MMIO regions need to have both reads and writes enabled */
106 if (!ctrl.we || !ctrl.re)
107 continue;
108
109 /* Non-posted region contains fixed FCH MMIO devices */
110 if (ctrl.np)
111 continue;
112
113 /* TODO: Systems with more than one PCI root need to check to which PCI root
114 the MMIO range gets decoded to. */
115
116 data_fabric_get_mmio_base_size(i, &mmio_base, &mmio_limit);
117
118 if (!is_mmio_region_valid(i, mmio_base, mmio_limit))
119 continue;
120
121 /* Make sure to not report a region overlapping with the fixed MMIO resources
122 below 4GB or the reserved MMIO range in the last 12GB of the addressable
123 address range. The code assumes that the fixed MMIO resources below 4GB
124 are between IO_APIC_ADDR and the 4GB boundary. */
125 if (mmio_base < 4ULL * GiB) {
126 if (mmio_base >= IO_APIC_ADDR)
127 continue;
128 if (mmio_limit >= IO_APIC_ADDR)
129 mmio_limit = IO_APIC_ADDR - 1;
130 } else {
131 if (mmio_base >= reserved_upper_mmio_base)
132 continue;
133 if (mmio_limit >= reserved_upper_mmio_base)
134 mmio_limit = reserved_upper_mmio_base - 1;
135 }
136
137 report_data_fabric_mmio(domain, (*idx)++, mmio_base, mmio_limit);
138 }
139}
140
141/* Tell the resource allocator about the usable I/O space */
142static void add_io_regions(struct device *domain, unsigned int *idx)
143{
144 struct resource *res;
145
146 /* TODO: Systems with more than one PCI root need to read the data fabric registers to
147 see which IO ranges get decoded to which PCI root. */
148
149 res = new_resource(domain, (*idx)++);
150 res->base = 0;
151 res->limit = 0xffff;
152 res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED;
153}
154
155void amd_pci_domain_read_resources(struct device *domain)
156{
157 unsigned int idx = 0;
158
159 add_io_regions(domain, &idx);
160
161 add_data_fabric_mmio_regions(domain, &idx);
162}
Felix Held7a5dd782023-04-28 22:47:33 +0200163
164static void write_ssdt_domain_io_producer_range_helper(const char *domain_name,
165 resource_t base, resource_t limit)
166{
167 printk(BIOS_DEBUG, "%s _CRS: adding IO range [%llx-%llx]\n", domain_name, base, limit);
168 acpigen_resource_producer_io(base, limit);
169}
170
171static void write_ssdt_domain_io_producer_range(const char *domain_name,
172 resource_t base, resource_t limit)
173{
174 /*
175 * Split the IO region at the PCI config IO ports so that the IO resource producer
176 * won't cover the same IO ports that the IO resource consumer for the PCI config IO
177 * ports in the same ACPI device already covers.
178 */
179 if (base < PCI_IO_CONFIG_INDEX) {
180 write_ssdt_domain_io_producer_range_helper(domain_name,
181 base,
182 MIN(limit, PCI_IO_CONFIG_INDEX - 1));
183 }
184 if (limit > PCI_IO_CONFIG_LAST_PORT) {
185 write_ssdt_domain_io_producer_range_helper(domain_name,
186 MAX(base, PCI_IO_CONFIG_LAST_PORT + 1),
187 limit);
188 }
189}
190
191static void write_ssdt_domain_mmio_producer_range(const char *domain_name,
192 resource_t base, resource_t limit)
193{
194 printk(BIOS_DEBUG, "%s _CRS: adding MMIO range [%llx-%llx]\n",
195 domain_name, base, limit);
196 acpigen_resource_producer_mmio(base, limit,
197 MEM_RSRC_FLAG_MEM_READ_WRITE | MEM_RSRC_FLAG_MEM_ATTR_NON_CACHE);
198}
199
200void amd_pci_domain_fill_ssdt(const struct device *domain)
201{
202 const char *acpi_scope = acpi_device_path(domain);
203 printk(BIOS_DEBUG, "%s ACPI scope: '%s'\n", __func__, acpi_scope);
204 acpigen_write_scope(acpi_device_path(domain));
205
206 acpigen_write_name("_CRS");
207 acpigen_write_resourcetemplate_header();
208
209 /* PCI bus number range in domain */
210 printk(BIOS_DEBUG, "%s _CRS: adding busses [%x-%x]\n", acpi_device_name(domain),
211 domain->link_list->secondary, domain->link_list->subordinate);
212 acpigen_resource_producer_bus_number(domain->link_list->secondary,
213 domain->link_list->subordinate);
214
215 if (domain->link_list->secondary == 0) {
216 /* ACPI 6.4.2.5 I/O Port Descriptor */
217 acpigen_write_io16(PCI_IO_CONFIG_INDEX, PCI_IO_CONFIG_LAST_PORT, 1,
218 PCI_IO_CONFIG_PORT_COUNT, 1);
219 }
220
221 struct resource *res;
222 for (res = domain->resource_list; res != NULL; res = res->next) {
223 if (!(res->flags & IORESOURCE_ASSIGNED))
224 return;
225 switch (res->flags & IORESOURCE_TYPE_MASK) {
226 case IORESOURCE_IO:
227 write_ssdt_domain_io_producer_range(acpi_device_name(domain),
228 res->base, res->limit);
229 break;
230 case IORESOURCE_MEM:
231 write_ssdt_domain_mmio_producer_range(acpi_device_name(domain),
232 res->base, res->limit);
233 break;
234 default:
235 break;
236 }
237 }
238
239 if (domain->link_list->bridge_ctrl & PCI_BRIDGE_CTL_VGA) {
240 printk(BIOS_DEBUG, "%s _CRS: adding VGA resource\n", acpi_device_name(domain));
241 acpigen_resource_producer_mmio(VGA_MMIO_BASE, VGA_MMIO_LIMIT,
242 MEM_RSRC_FLAG_MEM_READ_WRITE | MEM_RSRC_FLAG_MEM_ATTR_CACHE);
243 }
244
245 acpigen_write_resourcetemplate_footer();
246 /* Scope */
247 acpigen_pop_len();
248}