blob: 9b9ccc40123ee0b85c90679352853978ea595f78 [file] [log] [blame]
Felix Held407bd582023-04-24 17:58:24 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <amdblocks/cpu.h>
4#include <amdblocks/data_fabric.h>
5#include <arch/ioapic.h>
6#include <console/console.h>
7#include <cpu/amd/mtrr.h>
8#include <device/device.h>
9#include <device/pci_ops.h>
10#include <types.h>
11
12void amd_pci_domain_scan_bus(struct device *domain)
13{
14 uint8_t bus, limit;
15
16 /* TODO: Systems with more than one PCI root need to read the data fabric registers to
17 see which PCI bus numbers get decoded to which PCI root. */
18 bus = 0;
19 limit = CONFIG_ECAM_MMCONF_BUS_NUMBER - 1;
20
21 /* Set bus first number of PCI root */
22 domain->link_list->secondary = bus;
23 /* subordinate needs to be the same as secondary before pci_domain_scan_bus call. */
24 domain->link_list->subordinate = bus;
25
26 pci_domain_scan_bus(domain);
27
28 /* pci_domain_scan_bus will modify subordinate, so change it back to the maximum
29 bus number decoded to this PCI root for the acpigen_resource_producer_bus_number
30 call to write the correct ACPI code. */
31 domain->link_list->subordinate = limit;
32}
33
34/* Read the registers and return normalized values */
35static void data_fabric_get_mmio_base_size(unsigned int reg,
36 resource_t *mmio_base, resource_t *mmio_limit)
37{
38 const uint32_t base_reg = data_fabric_broadcast_read32(0, DF_MMIO_BASE(reg));
39 const uint32_t limit_reg = data_fabric_broadcast_read32(0, DF_MMIO_LIMIT(reg));
40 /* The raw register values are bits 47..16 of the actual address */
41 *mmio_base = (resource_t)base_reg << D18F0_MMIO_SHIFT;
42 *mmio_limit = (((resource_t)limit_reg + 1) << D18F0_MMIO_SHIFT) - 1;
43}
44
45static void print_df_mmio_outside_of_cpu_mmio_error(unsigned int reg)
46{
47 printk(BIOS_WARNING, "DF MMIO register %u outside of CPU MMIO region.\n", reg);
48}
49
50static bool is_mmio_region_valid(unsigned int reg, resource_t mmio_base, resource_t mmio_limit)
51{
52 if (mmio_base > mmio_limit) {
53 printk(BIOS_WARNING, "DF MMIO register %u's base is above its limit.\n", reg);
54 return false;
55 }
56 if (mmio_base >= 4ULL * GiB) {
57 /* MMIO region above 4GB needs to be above TOP_MEM2 MSR value */
58 if (mmio_base < get_top_of_mem_above_4gb()) {
59 print_df_mmio_outside_of_cpu_mmio_error(reg);
60 return false;
61 }
62 } else {
63 /* MMIO region below 4GB needs to be above TOP_MEM MSR value */
64 if (mmio_base < get_top_of_mem_below_4gb()) {
65 print_df_mmio_outside_of_cpu_mmio_error(reg);
66 return false;
67 }
68 /* MMIO region below 4GB mustn't cross the 4GB boundary. */
69 if (mmio_limit >= 4ULL * GiB) {
70 printk(BIOS_WARNING, "DF MMIO register %u crosses 4GB boundary.\n",
71 reg);
72 return false;
73 }
74 }
75
76 return true;
77}
78
79static void report_data_fabric_mmio(struct device *domain, unsigned int idx,
80 resource_t mmio_base, resource_t mmio_limit)
81{
82 struct resource *res;
83 res = new_resource(domain, idx);
84 res->base = mmio_base;
85 res->limit = mmio_limit;
86 res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED;
87}
88
89/* Tell the resource allocator about the usable MMIO ranges configured in the data fabric */
90static void add_data_fabric_mmio_regions(struct device *domain, unsigned int *idx)
91{
92 union df_mmio_control ctrl;
93 resource_t mmio_base;
94 resource_t mmio_limit;
95
96 /* The last 12GB of the usable address space are reserved and can't be used for MMIO */
97 const resource_t reserved_upper_mmio_base =
98 (1ULL << get_usable_physical_address_bits()) - DF_RESERVED_TOP_12GB_MMIO_SIZE;
99
100 for (unsigned int i = 0; i < DF_MMIO_REG_SET_COUNT; i++) {
101 ctrl.raw = data_fabric_broadcast_read32(0, DF_MMIO_CONTROL(i));
102
103 /* Relevant MMIO regions need to have both reads and writes enabled */
104 if (!ctrl.we || !ctrl.re)
105 continue;
106
107 /* Non-posted region contains fixed FCH MMIO devices */
108 if (ctrl.np)
109 continue;
110
111 /* TODO: Systems with more than one PCI root need to check to which PCI root
112 the MMIO range gets decoded to. */
113
114 data_fabric_get_mmio_base_size(i, &mmio_base, &mmio_limit);
115
116 if (!is_mmio_region_valid(i, mmio_base, mmio_limit))
117 continue;
118
119 /* Make sure to not report a region overlapping with the fixed MMIO resources
120 below 4GB or the reserved MMIO range in the last 12GB of the addressable
121 address range. The code assumes that the fixed MMIO resources below 4GB
122 are between IO_APIC_ADDR and the 4GB boundary. */
123 if (mmio_base < 4ULL * GiB) {
124 if (mmio_base >= IO_APIC_ADDR)
125 continue;
126 if (mmio_limit >= IO_APIC_ADDR)
127 mmio_limit = IO_APIC_ADDR - 1;
128 } else {
129 if (mmio_base >= reserved_upper_mmio_base)
130 continue;
131 if (mmio_limit >= reserved_upper_mmio_base)
132 mmio_limit = reserved_upper_mmio_base - 1;
133 }
134
135 report_data_fabric_mmio(domain, (*idx)++, mmio_base, mmio_limit);
136 }
137}
138
139/* Tell the resource allocator about the usable I/O space */
140static void add_io_regions(struct device *domain, unsigned int *idx)
141{
142 struct resource *res;
143
144 /* TODO: Systems with more than one PCI root need to read the data fabric registers to
145 see which IO ranges get decoded to which PCI root. */
146
147 res = new_resource(domain, (*idx)++);
148 res->base = 0;
149 res->limit = 0xffff;
150 res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED;
151}
152
153void amd_pci_domain_read_resources(struct device *domain)
154{
155 unsigned int idx = 0;
156
157 add_io_regions(domain, &idx);
158
159 add_data_fabric_mmio_regions(domain, &idx);
160}