blob: cfd4e0fe680940a954a742c155708fe26e6d2b8c [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>
Felix Held32169722023-07-14 19:41:06 +02006#include <amdblocks/root_complex.h>
Felix Held407bd582023-04-24 17:58:24 +02007#include <arch/ioapic.h>
Felix Held7a5dd782023-04-28 22:47:33 +02008#include <arch/vga.h>
Felix Held407bd582023-04-24 17:58:24 +02009#include <console/console.h>
10#include <cpu/amd/mtrr.h>
11#include <device/device.h>
12#include <device/pci_ops.h>
13#include <types.h>
14
15void amd_pci_domain_scan_bus(struct device *domain)
16{
17 uint8_t bus, limit;
18
19 /* TODO: Systems with more than one PCI root need to read the data fabric registers to
20 see which PCI bus numbers get decoded to which PCI root. */
21 bus = 0;
22 limit = CONFIG_ECAM_MMCONF_BUS_NUMBER - 1;
23
24 /* Set bus first number of PCI root */
25 domain->link_list->secondary = bus;
26 /* subordinate needs to be the same as secondary before pci_domain_scan_bus call. */
27 domain->link_list->subordinate = bus;
28
29 pci_domain_scan_bus(domain);
30
31 /* pci_domain_scan_bus will modify subordinate, so change it back to the maximum
32 bus number decoded to this PCI root for the acpigen_resource_producer_bus_number
33 call to write the correct ACPI code. */
34 domain->link_list->subordinate = limit;
35}
36
37/* Read the registers and return normalized values */
38static void data_fabric_get_mmio_base_size(unsigned int reg,
39 resource_t *mmio_base, resource_t *mmio_limit)
40{
Felix Held18a3c232023-08-03 00:10:03 +020041 const uint32_t base_reg = data_fabric_broadcast_read32(DF_MMIO_BASE(reg));
42 const uint32_t limit_reg = data_fabric_broadcast_read32(DF_MMIO_LIMIT(reg));
Felix Held407bd582023-04-24 17:58:24 +020043 /* The raw register values are bits 47..16 of the actual address */
Felix Held382c83e2023-08-03 00:29:55 +020044 *mmio_base = (resource_t)base_reg << DF_MMIO_SHIFT;
45 *mmio_limit = (((resource_t)limit_reg + 1) << DF_MMIO_SHIFT) - 1;
Felix Held407bd582023-04-24 17:58:24 +020046}
47
48static void print_df_mmio_outside_of_cpu_mmio_error(unsigned int reg)
49{
50 printk(BIOS_WARNING, "DF MMIO register %u outside of CPU MMIO region.\n", reg);
51}
52
53static bool is_mmio_region_valid(unsigned int reg, resource_t mmio_base, resource_t mmio_limit)
54{
55 if (mmio_base > mmio_limit) {
56 printk(BIOS_WARNING, "DF MMIO register %u's base is above its limit.\n", reg);
57 return false;
58 }
59 if (mmio_base >= 4ULL * GiB) {
60 /* MMIO region above 4GB needs to be above TOP_MEM2 MSR value */
61 if (mmio_base < get_top_of_mem_above_4gb()) {
62 print_df_mmio_outside_of_cpu_mmio_error(reg);
63 return false;
64 }
65 } else {
66 /* MMIO region below 4GB needs to be above TOP_MEM MSR value */
67 if (mmio_base < get_top_of_mem_below_4gb()) {
68 print_df_mmio_outside_of_cpu_mmio_error(reg);
69 return false;
70 }
71 /* MMIO region below 4GB mustn't cross the 4GB boundary. */
72 if (mmio_limit >= 4ULL * GiB) {
73 printk(BIOS_WARNING, "DF MMIO register %u crosses 4GB boundary.\n",
74 reg);
75 return false;
76 }
77 }
78
79 return true;
80}
81
82static void report_data_fabric_mmio(struct device *domain, unsigned int idx,
83 resource_t mmio_base, resource_t mmio_limit)
84{
85 struct resource *res;
86 res = new_resource(domain, idx);
87 res->base = mmio_base;
88 res->limit = mmio_limit;
89 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED;
90}
91
92/* Tell the resource allocator about the usable MMIO ranges configured in the data fabric */
93static void add_data_fabric_mmio_regions(struct device *domain, unsigned int *idx)
94{
95 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 =
101 (1ULL << get_usable_physical_address_bits()) - DF_RESERVED_TOP_12GB_MMIO_SIZE;
102
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
114 /* TODO: Systems with more than one PCI root need to check to which PCI root
115 the MMIO range gets decoded to. */
116
117 data_fabric_get_mmio_base_size(i, &mmio_base, &mmio_limit);
118
119 if (!is_mmio_region_valid(i, mmio_base, mmio_limit))
120 continue;
121
122 /* Make sure to not report a region overlapping with the fixed MMIO resources
123 below 4GB or the reserved MMIO range in the last 12GB of the addressable
124 address range. The code assumes that the fixed MMIO resources below 4GB
125 are between IO_APIC_ADDR and the 4GB boundary. */
126 if (mmio_base < 4ULL * GiB) {
127 if (mmio_base >= IO_APIC_ADDR)
128 continue;
129 if (mmio_limit >= IO_APIC_ADDR)
130 mmio_limit = IO_APIC_ADDR - 1;
131 } else {
132 if (mmio_base >= reserved_upper_mmio_base)
133 continue;
134 if (mmio_limit >= reserved_upper_mmio_base)
135 mmio_limit = reserved_upper_mmio_base - 1;
136 }
137
138 report_data_fabric_mmio(domain, (*idx)++, mmio_base, mmio_limit);
139 }
140}
141
Felix Held2dfd48b2023-08-04 19:22:54 +0200142static void report_data_fabric_io(struct device *domain, unsigned int idx,
143 resource_t io_base, resource_t io_limit)
144{
145 struct resource *res;
146 res = new_resource(domain, idx);
147 res->base = io_base;
148 res->limit = io_limit;
149 res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED;
150}
151
Felix Held407bd582023-04-24 17:58:24 +0200152/* Tell the resource allocator about the usable I/O space */
Felix Held3f3f93b2023-08-04 22:14:40 +0200153static void add_data_fabric_io_regions(struct device *domain, unsigned int *idx)
Felix Held407bd582023-04-24 17:58:24 +0200154{
Felix Held407bd582023-04-24 17:58:24 +0200155 /* TODO: Systems with more than one PCI root need to read the data fabric registers to
156 see which IO ranges get decoded to which PCI root. */
157
Felix Held2dfd48b2023-08-04 19:22:54 +0200158 report_data_fabric_io(domain, (*idx)++, 0, 0xffff);
Felix Held407bd582023-04-24 17:58:24 +0200159}
160
161void amd_pci_domain_read_resources(struct device *domain)
162{
163 unsigned int idx = 0;
164
Felix Held3f3f93b2023-08-04 22:14:40 +0200165 add_data_fabric_io_regions(domain, &idx);
Felix Held407bd582023-04-24 17:58:24 +0200166
167 add_data_fabric_mmio_regions(domain, &idx);
Felix Held32169722023-07-14 19:41:06 +0200168
169 read_non_pci_resources(domain, &idx);
Felix Held407bd582023-04-24 17:58:24 +0200170}
Felix Held7a5dd782023-04-28 22:47:33 +0200171
172static void write_ssdt_domain_io_producer_range_helper(const char *domain_name,
173 resource_t base, resource_t limit)
174{
175 printk(BIOS_DEBUG, "%s _CRS: adding IO range [%llx-%llx]\n", domain_name, base, limit);
176 acpigen_resource_producer_io(base, limit);
177}
178
179static void write_ssdt_domain_io_producer_range(const char *domain_name,
180 resource_t base, resource_t limit)
181{
182 /*
183 * Split the IO region at the PCI config IO ports so that the IO resource producer
184 * won't cover the same IO ports that the IO resource consumer for the PCI config IO
185 * ports in the same ACPI device already covers.
186 */
187 if (base < PCI_IO_CONFIG_INDEX) {
188 write_ssdt_domain_io_producer_range_helper(domain_name,
189 base,
190 MIN(limit, PCI_IO_CONFIG_INDEX - 1));
191 }
192 if (limit > PCI_IO_CONFIG_LAST_PORT) {
193 write_ssdt_domain_io_producer_range_helper(domain_name,
194 MAX(base, PCI_IO_CONFIG_LAST_PORT + 1),
195 limit);
196 }
197}
198
199static void write_ssdt_domain_mmio_producer_range(const char *domain_name,
200 resource_t base, resource_t limit)
201{
202 printk(BIOS_DEBUG, "%s _CRS: adding MMIO range [%llx-%llx]\n",
203 domain_name, base, limit);
204 acpigen_resource_producer_mmio(base, limit,
205 MEM_RSRC_FLAG_MEM_READ_WRITE | MEM_RSRC_FLAG_MEM_ATTR_NON_CACHE);
206}
207
208void amd_pci_domain_fill_ssdt(const struct device *domain)
209{
210 const char *acpi_scope = acpi_device_path(domain);
211 printk(BIOS_DEBUG, "%s ACPI scope: '%s'\n", __func__, acpi_scope);
212 acpigen_write_scope(acpi_device_path(domain));
213
214 acpigen_write_name("_CRS");
215 acpigen_write_resourcetemplate_header();
216
217 /* PCI bus number range in domain */
218 printk(BIOS_DEBUG, "%s _CRS: adding busses [%x-%x]\n", acpi_device_name(domain),
219 domain->link_list->secondary, domain->link_list->subordinate);
220 acpigen_resource_producer_bus_number(domain->link_list->secondary,
221 domain->link_list->subordinate);
222
223 if (domain->link_list->secondary == 0) {
224 /* ACPI 6.4.2.5 I/O Port Descriptor */
225 acpigen_write_io16(PCI_IO_CONFIG_INDEX, PCI_IO_CONFIG_LAST_PORT, 1,
226 PCI_IO_CONFIG_PORT_COUNT, 1);
227 }
228
229 struct resource *res;
230 for (res = domain->resource_list; res != NULL; res = res->next) {
231 if (!(res->flags & IORESOURCE_ASSIGNED))
Felix Helda239cf42023-07-29 01:45:31 +0200232 continue;
Felix Held0df754b2023-07-29 01:49:15 +0200233 /* Don't add MMIO producer ranges for reserved MMIO regions from non-PCI
234 devices */
235 if ((res->flags & IORESOURCE_RESERVE))
236 continue;
Felix Held7a5dd782023-04-28 22:47:33 +0200237 switch (res->flags & IORESOURCE_TYPE_MASK) {
238 case IORESOURCE_IO:
239 write_ssdt_domain_io_producer_range(acpi_device_name(domain),
240 res->base, res->limit);
241 break;
242 case IORESOURCE_MEM:
243 write_ssdt_domain_mmio_producer_range(acpi_device_name(domain),
244 res->base, res->limit);
245 break;
246 default:
247 break;
248 }
249 }
250
251 if (domain->link_list->bridge_ctrl & PCI_BRIDGE_CTL_VGA) {
252 printk(BIOS_DEBUG, "%s _CRS: adding VGA resource\n", acpi_device_name(domain));
253 acpigen_resource_producer_mmio(VGA_MMIO_BASE, VGA_MMIO_LIMIT,
254 MEM_RSRC_FLAG_MEM_READ_WRITE | MEM_RSRC_FLAG_MEM_ATTR_CACHE);
255 }
256
257 acpigen_write_resourcetemplate_footer();
Felix Helde4b65cc2023-05-05 20:46:11 +0200258
259 acpigen_write_BBN(domain->link_list->secondary);
260
Felix Held7a5dd782023-04-28 22:47:33 +0200261 /* Scope */
262 acpigen_pop_len();
263}