blob: b056d607c74920806734d5786c6719e0b339a6c2 [file] [log] [blame]
Felix Held407bd582023-04-24 17:58:24 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2
Felix Held407bd582023-04-24 17:58:24 +02003#include <amdblocks/data_fabric.h>
Felix Held32169722023-07-14 19:41:06 +02004#include <amdblocks/root_complex.h>
Felix Held407bd582023-04-24 17:58:24 +02005#include <arch/ioapic.h>
6#include <console/console.h>
7#include <cpu/amd/mtrr.h>
Felix Held89ca4782023-09-12 15:01:02 +02008#include <cpu/cpu.h>
Felix Held407bd582023-04-24 17:58:24 +02009#include <device/device.h>
Felix Held3b5b66d2024-01-11 22:26:18 +010010#include <device/pci.h>
Felix Held407bd582023-04-24 17:58:24 +020011#include <device/pci_ops.h>
12#include <types.h>
13
14void amd_pci_domain_scan_bus(struct device *domain)
15{
Felix Held6c00a6a2023-12-06 23:40:42 +010016 uint8_t segment_group, bus, limit;
Felix Held407bd582023-04-24 17:58:24 +020017
Felix Held6c00a6a2023-12-06 23:40:42 +010018 if (data_fabric_get_pci_bus_numbers(domain, &segment_group, &bus, &limit) != CB_SUCCESS) {
Felix Heldea831392023-08-08 02:55:09 +020019 printk(BIOS_ERR, "No PCI bus numbers decoded to PCI root.\n");
20 return;
21 }
22
Felix Held3b5b66d2024-01-11 22:26:18 +010023 if (segment_group >= PCI_SEGMENT_GROUP_COUNT) {
24 printk(BIOS_ERR, "Skipping domain %u due to too large segment group %u.\n",
25 domain->path.domain.domain, segment_group);
Felix Held6c00a6a2023-12-06 23:40:42 +010026 return;
27 }
28
Felix Held3b5b66d2024-01-11 22:26:18 +010029 /* TODO: Check if bus >= PCI_BUSES_PER_SEGMENT_GROUP and return in that case */
Felix Heldea831392023-08-08 02:55:09 +020030
Felix Held3b5b66d2024-01-11 22:26:18 +010031 /* Make sure to not report more than PCI_BUSES_PER_SEGMENT_GROUP PCI buses */
32 limit = MIN(limit, PCI_BUSES_PER_SEGMENT_GROUP - 1);
Felix Held407bd582023-04-24 17:58:24 +020033
34 /* Set bus first number of PCI root */
Arthur Heymans7fcd4d52023-08-24 15:12:19 +020035 domain->downstream->secondary = bus;
Arthur Heymans0b0113f2023-08-31 17:09:28 +020036 /* subordinate needs to be the same as secondary before pci_host_bridge_scan_bus call. */
Arthur Heymans7fcd4d52023-08-24 15:12:19 +020037 domain->downstream->subordinate = bus;
Felix Held9dcdec52023-08-08 21:38:43 +020038 /* Tell allocator about maximum PCI bus number in domain */
Arthur Heymans7fcd4d52023-08-24 15:12:19 +020039 domain->downstream->max_subordinate = limit;
40 domain->downstream->segment_group = segment_group;
Felix Held407bd582023-04-24 17:58:24 +020041
Arthur Heymans0b0113f2023-08-31 17:09:28 +020042 pci_host_bridge_scan_bus(domain);
Felix Held407bd582023-04-24 17:58:24 +020043}
44
Felix Held407bd582023-04-24 17:58:24 +020045static 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
Felix Helde4594f12024-01-30 22:04:34 +010079static void report_data_fabric_mmio(struct device *domain, unsigned long idx,
Felix Held407bd582023-04-24 17:58:24 +020080 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 */
Felix Helde4594f12024-01-30 22:04:34 +010090static void add_data_fabric_mmio_regions(struct device *domain, unsigned long *idx)
Felix Held407bd582023-04-24 17:58:24 +020091{
Felix Held9cbdc8f2023-08-11 22:30:06 +020092 const signed int iohc_dest_fabric_id = get_iohc_fabric_id(domain);
Felix Held407bd582023-04-24 17:58:24 +020093 union df_mmio_control ctrl;
94 resource_t mmio_base;
95 resource_t mmio_limit;
96
97 /* The last 12GB of the usable address space are reserved and can't be used for MMIO */
98 const resource_t reserved_upper_mmio_base =
Felix Held89ca4782023-09-12 15:01:02 +020099 (1ULL << cpu_phys_address_size()) - DF_RESERVED_TOP_12GB_MMIO_SIZE;
Felix Held407bd582023-04-24 17:58:24 +0200100
101 for (unsigned int i = 0; i < DF_MMIO_REG_SET_COUNT; i++) {
Felix Held18a3c232023-08-03 00:10:03 +0200102 ctrl.raw = data_fabric_broadcast_read32(DF_MMIO_CONTROL(i));
Felix Held407bd582023-04-24 17:58:24 +0200103
104 /* Relevant MMIO regions need to have both reads and writes enabled */
105 if (!ctrl.we || !ctrl.re)
106 continue;
107
108 /* Non-posted region contains fixed FCH MMIO devices */
109 if (ctrl.np)
110 continue;
111
Felix Held55822d92023-08-08 21:38:07 +0200112 /* Only look at MMIO regions that are decoded to the right PCI root */
Felix Held9cbdc8f2023-08-11 22:30:06 +0200113 if (ctrl.dst_fabric_id != iohc_dest_fabric_id)
Felix Held55822d92023-08-08 21:38:07 +0200114 continue;
Felix Held407bd582023-04-24 17:58:24 +0200115
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
Felix Helde4594f12024-01-30 22:04:34 +0100141static void report_data_fabric_io(struct device *domain, unsigned long idx,
Felix Held2dfd48b2023-08-04 19:22:54 +0200142 resource_t io_base, resource_t io_limit)
143{
144 struct resource *res;
145 res = new_resource(domain, idx);
146 res->base = io_base;
147 res->limit = io_limit;
148 res->flags = IORESOURCE_IO | IORESOURCE_ASSIGNED;
149}
150
Felix Held407bd582023-04-24 17:58:24 +0200151/* Tell the resource allocator about the usable I/O space */
Felix Helde4594f12024-01-30 22:04:34 +0100152static void add_data_fabric_io_regions(struct device *domain, unsigned long *idx)
Felix Held407bd582023-04-24 17:58:24 +0200153{
Felix Held9cbdc8f2023-08-11 22:30:06 +0200154 const signed int iohc_dest_fabric_id = get_iohc_fabric_id(domain);
Felix Held4eac0d42023-08-04 19:40:02 +0200155 union df_io_base base_reg;
156 union df_io_limit limit_reg;
157 resource_t io_base;
158 resource_t io_limit;
Felix Held407bd582023-04-24 17:58:24 +0200159
Felix Held4eac0d42023-08-04 19:40:02 +0200160 for (unsigned int i = 0; i < DF_IO_REG_COUNT; i++) {
161 base_reg.raw = data_fabric_broadcast_read32(DF_IO_BASE(i));
162
163 /* Relevant IO regions need to have both reads and writes enabled */
164 if (!base_reg.we || !base_reg.re)
165 continue;
166
167 limit_reg.raw = data_fabric_broadcast_read32(DF_IO_LIMIT(i));
168
Felix Held55822d92023-08-08 21:38:07 +0200169 /* Only look at IO regions that are decoded to the right PCI root */
Felix Held9cbdc8f2023-08-11 22:30:06 +0200170 if (limit_reg.dst_fabric_id != iohc_dest_fabric_id)
Felix Held55822d92023-08-08 21:38:07 +0200171 continue;
Felix Held4eac0d42023-08-04 19:40:02 +0200172
173 io_base = base_reg.io_base << DF_IO_ADDR_SHIFT;
174 io_limit = ((limit_reg.io_limit + 1) << DF_IO_ADDR_SHIFT) - 1;
175
176 /* Beware that the lower 25 bits of io_base and io_limit can be non-zero
177 despite there only being 16 bits worth of IO port address space. */
178 if (io_base > 0xffff) {
179 printk(BIOS_WARNING, "DF IO base register %d value outside of valid "
180 "IO port address range.\n", i);
181 continue;
182 }
183 /* If only the IO limit is outside of the valid 16 bit IO port range, report
184 the limit as 0xffff, so that the resource allcator won't put IO BARs outside
185 of the 16 bit IO port address range. */
186 io_limit = MIN(io_limit, 0xffff);
187
188 report_data_fabric_io(domain, (*idx)++, io_base, io_limit);
189 }
Felix Held407bd582023-04-24 17:58:24 +0200190}
191
Felix Helddde265f2024-01-30 15:40:53 +0100192static void add_pci_cfg_resources(struct device *domain, unsigned long *idx)
193{
194 fixed_io_range_reserved(domain, (*idx)++, PCI_IO_CONFIG_INDEX, PCI_IO_CONFIG_PORT_COUNT);
195 mmconf_resource(domain, (*idx)++);
196}
197
Felix Held407bd582023-04-24 17:58:24 +0200198void amd_pci_domain_read_resources(struct device *domain)
199{
Felix Helde4594f12024-01-30 22:04:34 +0100200 unsigned long idx = 0;
Felix Held407bd582023-04-24 17:58:24 +0200201
Felix Held3f3f93b2023-08-04 22:14:40 +0200202 add_data_fabric_io_regions(domain, &idx);
Felix Held407bd582023-04-24 17:58:24 +0200203
204 add_data_fabric_mmio_regions(domain, &idx);
Felix Held32169722023-07-14 19:41:06 +0200205
206 read_non_pci_resources(domain, &idx);
Felix Held30f36c32024-01-30 15:15:31 +0100207
208 /* Only add the SoC's DRAM memory map and fixed resources once */
209 if (domain->path.domain.domain == 0) {
Felix Helddde265f2024-01-30 15:40:53 +0100210 add_pci_cfg_resources(domain, &idx);
211
Felix Held30f36c32024-01-30 15:15:31 +0100212 read_soc_memmap_resources(domain, &idx);
213 }
Felix Held407bd582023-04-24 17:58:24 +0200214}