blob: 39243514cc766562b8d0ae9ece3f645a85fbf6d9 [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
Felix Heldea831392023-08-08 02:55:09 +020019 if (data_fabric_get_pci_bus_numbers(domain, &bus, &limit) != CB_SUCCESS) {
20 printk(BIOS_ERR, "No PCI bus numbers decoded to PCI root.\n");
21 return;
22 }
23
24 /* TODO: Check if bus >= CONFIG_ECAM_MMCONF_BUS_NUMBER and return in that case */
25
26 /* Make sure to not report more than CONFIG_ECAM_MMCONF_BUS_NUMBER PCI buses */
27 limit = MIN(limit, CONFIG_ECAM_MMCONF_BUS_NUMBER - 1);
Felix Held407bd582023-04-24 17:58:24 +020028
29 /* Set bus first number of PCI root */
30 domain->link_list->secondary = bus;
31 /* subordinate needs to be the same as secondary before pci_domain_scan_bus call. */
32 domain->link_list->subordinate = bus;
Felix Held9dcdec52023-08-08 21:38:43 +020033 /* Tell allocator about maximum PCI bus number in domain */
34 domain->link_list->max_subordinate = limit;
Felix Held407bd582023-04-24 17:58:24 +020035
36 pci_domain_scan_bus(domain);
Felix Held407bd582023-04-24 17:58:24 +020037}
38
39/* Read the registers and return normalized values */
40static void data_fabric_get_mmio_base_size(unsigned int reg,
41 resource_t *mmio_base, resource_t *mmio_limit)
42{
Felix Held18a3c232023-08-03 00:10:03 +020043 const uint32_t base_reg = data_fabric_broadcast_read32(DF_MMIO_BASE(reg));
44 const uint32_t limit_reg = data_fabric_broadcast_read32(DF_MMIO_LIMIT(reg));
Felix Held407bd582023-04-24 17:58:24 +020045 /* The raw register values are bits 47..16 of the actual address */
Felix Held382c83e2023-08-03 00:29:55 +020046 *mmio_base = (resource_t)base_reg << DF_MMIO_SHIFT;
47 *mmio_limit = (((resource_t)limit_reg + 1) << DF_MMIO_SHIFT) - 1;
Felix Held407bd582023-04-24 17:58:24 +020048}
49
50static void print_df_mmio_outside_of_cpu_mmio_error(unsigned int reg)
51{
52 printk(BIOS_WARNING, "DF MMIO register %u outside of CPU MMIO region.\n", reg);
53}
54
55static bool is_mmio_region_valid(unsigned int reg, resource_t mmio_base, resource_t mmio_limit)
56{
57 if (mmio_base > mmio_limit) {
58 printk(BIOS_WARNING, "DF MMIO register %u's base is above its limit.\n", reg);
59 return false;
60 }
61 if (mmio_base >= 4ULL * GiB) {
62 /* MMIO region above 4GB needs to be above TOP_MEM2 MSR value */
63 if (mmio_base < get_top_of_mem_above_4gb()) {
64 print_df_mmio_outside_of_cpu_mmio_error(reg);
65 return false;
66 }
67 } else {
68 /* MMIO region below 4GB needs to be above TOP_MEM MSR value */
69 if (mmio_base < get_top_of_mem_below_4gb()) {
70 print_df_mmio_outside_of_cpu_mmio_error(reg);
71 return false;
72 }
73 /* MMIO region below 4GB mustn't cross the 4GB boundary. */
74 if (mmio_limit >= 4ULL * GiB) {
75 printk(BIOS_WARNING, "DF MMIO register %u crosses 4GB boundary.\n",
76 reg);
77 return false;
78 }
79 }
80
81 return true;
82}
83
84static void report_data_fabric_mmio(struct device *domain, unsigned int idx,
85 resource_t mmio_base, resource_t mmio_limit)
86{
87 struct resource *res;
88 res = new_resource(domain, idx);
89 res->base = mmio_base;
90 res->limit = mmio_limit;
91 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED;
92}
93
94/* Tell the resource allocator about the usable MMIO ranges configured in the data fabric */
95static void add_data_fabric_mmio_regions(struct device *domain, unsigned int *idx)
96{
97 union df_mmio_control ctrl;
98 resource_t mmio_base;
99 resource_t mmio_limit;
100
101 /* The last 12GB of the usable address space are reserved and can't be used for MMIO */
102 const resource_t reserved_upper_mmio_base =
103 (1ULL << get_usable_physical_address_bits()) - DF_RESERVED_TOP_12GB_MMIO_SIZE;
104
105 for (unsigned int i = 0; i < DF_MMIO_REG_SET_COUNT; i++) {
Felix Held18a3c232023-08-03 00:10:03 +0200106 ctrl.raw = data_fabric_broadcast_read32(DF_MMIO_CONTROL(i));
Felix Held407bd582023-04-24 17:58:24 +0200107
108 /* Relevant MMIO regions need to have both reads and writes enabled */
109 if (!ctrl.we || !ctrl.re)
110 continue;
111
112 /* Non-posted region contains fixed FCH MMIO devices */
113 if (ctrl.np)
114 continue;
115
Felix Held55822d92023-08-08 21:38:07 +0200116 /* Only look at MMIO regions that are decoded to the right PCI root */
117 if (CONFIG(SOC_AMD_COMMON_BLOCK_DATA_FABRIC_DOMAIN_MULTI_PCI_ROOT) &&
118 ctrl.dst_fabric_id != domain->path.domain.domain)
119 continue;
Felix Held407bd582023-04-24 17:58:24 +0200120
121 data_fabric_get_mmio_base_size(i, &mmio_base, &mmio_limit);
122
123 if (!is_mmio_region_valid(i, mmio_base, mmio_limit))
124 continue;
125
126 /* Make sure to not report a region overlapping with the fixed MMIO resources
127 below 4GB or the reserved MMIO range in the last 12GB of the addressable
128 address range. The code assumes that the fixed MMIO resources below 4GB
129 are between IO_APIC_ADDR and the 4GB boundary. */
130 if (mmio_base < 4ULL * GiB) {
131 if (mmio_base >= IO_APIC_ADDR)
132 continue;
133 if (mmio_limit >= IO_APIC_ADDR)
134 mmio_limit = IO_APIC_ADDR - 1;
135 } else {
136 if (mmio_base >= reserved_upper_mmio_base)
137 continue;
138 if (mmio_limit >= reserved_upper_mmio_base)
139 mmio_limit = reserved_upper_mmio_base - 1;
140 }
141
142 report_data_fabric_mmio(domain, (*idx)++, mmio_base, mmio_limit);
143 }
144}
145
Felix Held2dfd48b2023-08-04 19:22:54 +0200146static void report_data_fabric_io(struct device *domain, unsigned int idx,
147 resource_t io_base, resource_t io_limit)
148{
149 struct resource *res;
150 res = new_resource(domain, idx);
151 res->base = io_base;
152 res->limit = io_limit;
153 res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED;
154}
155
Felix Held407bd582023-04-24 17:58:24 +0200156/* Tell the resource allocator about the usable I/O space */
Felix Held3f3f93b2023-08-04 22:14:40 +0200157static void add_data_fabric_io_regions(struct device *domain, unsigned int *idx)
Felix Held407bd582023-04-24 17:58:24 +0200158{
Felix Held4eac0d42023-08-04 19:40:02 +0200159 union df_io_base base_reg;
160 union df_io_limit limit_reg;
161 resource_t io_base;
162 resource_t io_limit;
Felix Held407bd582023-04-24 17:58:24 +0200163
Felix Held4eac0d42023-08-04 19:40:02 +0200164 for (unsigned int i = 0; i < DF_IO_REG_COUNT; i++) {
165 base_reg.raw = data_fabric_broadcast_read32(DF_IO_BASE(i));
166
167 /* Relevant IO regions need to have both reads and writes enabled */
168 if (!base_reg.we || !base_reg.re)
169 continue;
170
171 limit_reg.raw = data_fabric_broadcast_read32(DF_IO_LIMIT(i));
172
Felix Held55822d92023-08-08 21:38:07 +0200173 /* Only look at IO regions that are decoded to the right PCI root */
174 if (CONFIG(SOC_AMD_COMMON_BLOCK_DATA_FABRIC_DOMAIN_MULTI_PCI_ROOT) &&
175 limit_reg.dst_fabric_id != domain->path.domain.domain)
176 continue;
Felix Held4eac0d42023-08-04 19:40:02 +0200177
178 io_base = base_reg.io_base << DF_IO_ADDR_SHIFT;
179 io_limit = ((limit_reg.io_limit + 1) << DF_IO_ADDR_SHIFT) - 1;
180
181 /* Beware that the lower 25 bits of io_base and io_limit can be non-zero
182 despite there only being 16 bits worth of IO port address space. */
183 if (io_base > 0xffff) {
184 printk(BIOS_WARNING, "DF IO base register %d value outside of valid "
185 "IO port address range.\n", i);
186 continue;
187 }
188 /* If only the IO limit is outside of the valid 16 bit IO port range, report
189 the limit as 0xffff, so that the resource allcator won't put IO BARs outside
190 of the 16 bit IO port address range. */
191 io_limit = MIN(io_limit, 0xffff);
192
193 report_data_fabric_io(domain, (*idx)++, io_base, io_limit);
194 }
Felix Held407bd582023-04-24 17:58:24 +0200195}
196
197void amd_pci_domain_read_resources(struct device *domain)
198{
199 unsigned int idx = 0;
200
Felix Held3f3f93b2023-08-04 22:14:40 +0200201 add_data_fabric_io_regions(domain, &idx);
Felix Held407bd582023-04-24 17:58:24 +0200202
203 add_data_fabric_mmio_regions(domain, &idx);
Felix Held32169722023-07-14 19:41:06 +0200204
205 read_non_pci_resources(domain, &idx);
Felix Held407bd582023-04-24 17:58:24 +0200206}
Felix Held7a5dd782023-04-28 22:47:33 +0200207
208static void write_ssdt_domain_io_producer_range_helper(const char *domain_name,
209 resource_t base, resource_t limit)
210{
211 printk(BIOS_DEBUG, "%s _CRS: adding IO range [%llx-%llx]\n", domain_name, base, limit);
212 acpigen_resource_producer_io(base, limit);
213}
214
215static void write_ssdt_domain_io_producer_range(const char *domain_name,
216 resource_t base, resource_t limit)
217{
218 /*
219 * Split the IO region at the PCI config IO ports so that the IO resource producer
220 * won't cover the same IO ports that the IO resource consumer for the PCI config IO
221 * ports in the same ACPI device already covers.
222 */
223 if (base < PCI_IO_CONFIG_INDEX) {
224 write_ssdt_domain_io_producer_range_helper(domain_name,
225 base,
226 MIN(limit, PCI_IO_CONFIG_INDEX - 1));
227 }
228 if (limit > PCI_IO_CONFIG_LAST_PORT) {
229 write_ssdt_domain_io_producer_range_helper(domain_name,
230 MAX(base, PCI_IO_CONFIG_LAST_PORT + 1),
231 limit);
232 }
233}
234
235static void write_ssdt_domain_mmio_producer_range(const char *domain_name,
236 resource_t base, resource_t limit)
237{
238 printk(BIOS_DEBUG, "%s _CRS: adding MMIO range [%llx-%llx]\n",
239 domain_name, base, limit);
240 acpigen_resource_producer_mmio(base, limit,
241 MEM_RSRC_FLAG_MEM_READ_WRITE | MEM_RSRC_FLAG_MEM_ATTR_NON_CACHE);
242}
243
244void amd_pci_domain_fill_ssdt(const struct device *domain)
245{
246 const char *acpi_scope = acpi_device_path(domain);
247 printk(BIOS_DEBUG, "%s ACPI scope: '%s'\n", __func__, acpi_scope);
248 acpigen_write_scope(acpi_device_path(domain));
249
250 acpigen_write_name("_CRS");
251 acpigen_write_resourcetemplate_header();
252
253 /* PCI bus number range in domain */
254 printk(BIOS_DEBUG, "%s _CRS: adding busses [%x-%x]\n", acpi_device_name(domain),
Felix Held9dcdec52023-08-08 21:38:43 +0200255 domain->link_list->secondary, domain->link_list->max_subordinate);
Felix Held7a5dd782023-04-28 22:47:33 +0200256 acpigen_resource_producer_bus_number(domain->link_list->secondary,
Felix Held9dcdec52023-08-08 21:38:43 +0200257 domain->link_list->max_subordinate);
Felix Held7a5dd782023-04-28 22:47:33 +0200258
259 if (domain->link_list->secondary == 0) {
260 /* ACPI 6.4.2.5 I/O Port Descriptor */
261 acpigen_write_io16(PCI_IO_CONFIG_INDEX, PCI_IO_CONFIG_LAST_PORT, 1,
262 PCI_IO_CONFIG_PORT_COUNT, 1);
263 }
264
265 struct resource *res;
266 for (res = domain->resource_list; res != NULL; res = res->next) {
267 if (!(res->flags & IORESOURCE_ASSIGNED))
Felix Helda239cf42023-07-29 01:45:31 +0200268 continue;
Felix Held0df754b2023-07-29 01:49:15 +0200269 /* Don't add MMIO producer ranges for reserved MMIO regions from non-PCI
270 devices */
271 if ((res->flags & IORESOURCE_RESERVE))
272 continue;
Felix Held7a5dd782023-04-28 22:47:33 +0200273 switch (res->flags & IORESOURCE_TYPE_MASK) {
274 case IORESOURCE_IO:
275 write_ssdt_domain_io_producer_range(acpi_device_name(domain),
276 res->base, res->limit);
277 break;
278 case IORESOURCE_MEM:
279 write_ssdt_domain_mmio_producer_range(acpi_device_name(domain),
280 res->base, res->limit);
281 break;
282 default:
283 break;
284 }
285 }
286
287 if (domain->link_list->bridge_ctrl & PCI_BRIDGE_CTL_VGA) {
288 printk(BIOS_DEBUG, "%s _CRS: adding VGA resource\n", acpi_device_name(domain));
289 acpigen_resource_producer_mmio(VGA_MMIO_BASE, VGA_MMIO_LIMIT,
290 MEM_RSRC_FLAG_MEM_READ_WRITE | MEM_RSRC_FLAG_MEM_ATTR_CACHE);
291 }
292
293 acpigen_write_resourcetemplate_footer();
Felix Helde4b65cc2023-05-05 20:46:11 +0200294
295 acpigen_write_BBN(domain->link_list->secondary);
296
Felix Held7a5dd782023-04-28 22:47:33 +0200297 /* Scope */
298 acpigen_pop_len();
299}