xref: /aosp_15_r20/external/coreboot/src/soc/amd/common/block/data_fabric/domain.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-only */
2 
3 #include <amdblocks/data_fabric.h>
4 #include <amdblocks/root_complex.h>
5 #include <arch/ioapic.h>
6 #include <console/console.h>
7 #include <cpu/amd/mtrr.h>
8 #include <cpu/cpu.h>
9 #include <device/device.h>
10 #include <device/pci.h>
11 #include <device/pci_ops.h>
12 #include <types.h>
13 
amd_pci_domain_scan_bus(struct device * domain)14 void amd_pci_domain_scan_bus(struct device *domain)
15 {
16 	uint8_t segment_group, bus, limit;
17 
18 	if (data_fabric_get_pci_bus_numbers(domain, &segment_group, &bus, &limit) != CB_SUCCESS) {
19 		printk(BIOS_ERR, "No PCI bus numbers decoded to PCI root.\n");
20 		return;
21 	}
22 
23 	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);
26 		return;
27 	}
28 
29 	/* TODO: Check if bus >= PCI_BUSES_PER_SEGMENT_GROUP and return in that case */
30 
31 	/* Make sure to not report more than PCI_BUSES_PER_SEGMENT_GROUP PCI buses */
32 	limit = MIN(limit, PCI_BUSES_PER_SEGMENT_GROUP - 1);
33 
34 	/* Set bus first number of PCI root */
35 	domain->downstream->secondary = bus;
36 	/* subordinate needs to be the same as secondary before pci_host_bridge_scan_bus call. */
37 	domain->downstream->subordinate = bus;
38 	/* Tell allocator about maximum PCI bus number in domain */
39 	domain->downstream->max_subordinate = limit;
40 	domain->downstream->segment_group = segment_group;
41 
42 	pci_host_bridge_scan_bus(domain);
43 }
44 
print_df_mmio_outside_of_cpu_mmio_error(unsigned int reg)45 static 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 
is_mmio_region_valid(unsigned int reg,resource_t mmio_base,resource_t mmio_limit)50 static 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 
report_data_fabric_mmio(struct device * domain,unsigned long idx,resource_t mmio_base,resource_t mmio_limit)79 static void report_data_fabric_mmio(struct device *domain, unsigned long 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 */
add_data_fabric_mmio_regions(struct device * domain,unsigned long * idx)90 static void add_data_fabric_mmio_regions(struct device *domain, unsigned long *idx)
91 {
92 	const signed int iohc_dest_fabric_id = get_iohc_fabric_id(domain);
93 	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 =
99 		(1ULL << cpu_phys_address_size()) - DF_RESERVED_TOP_12GB_MMIO_SIZE;
100 
101 	for (unsigned int i = 0; i < DF_MMIO_REG_SET_COUNT; i++) {
102 		ctrl.raw = data_fabric_broadcast_read32(DF_MMIO_CONTROL(i));
103 
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 
112 		/* Only look at MMIO regions that are decoded to the right PCI root */
113 		if (ctrl.dst_fabric_id != iohc_dest_fabric_id)
114 			continue;
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 
report_data_fabric_io(struct device * domain,unsigned long idx,resource_t io_base,resource_t io_limit)141 static void report_data_fabric_io(struct device *domain, unsigned long idx,
142 				  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 
151 /* Tell the resource allocator about the usable I/O space */
add_data_fabric_io_regions(struct device * domain,unsigned long * idx)152 static void add_data_fabric_io_regions(struct device *domain, unsigned long *idx)
153 {
154 	const signed int iohc_dest_fabric_id = get_iohc_fabric_id(domain);
155 	union df_io_base base_reg;
156 	union df_io_limit limit_reg;
157 	resource_t io_base;
158 	resource_t io_limit;
159 
160 	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 
169 		/* Only look at IO regions that are decoded to the right PCI root */
170 		if (limit_reg.dst_fabric_id != iohc_dest_fabric_id)
171 			continue;
172 
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 	}
190 }
191 
add_pci_cfg_resources(struct device * domain,unsigned long * idx)192 static 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 
amd_pci_domain_read_resources(struct device * domain)198 void amd_pci_domain_read_resources(struct device *domain)
199 {
200 	unsigned long idx = 0;
201 
202 	add_data_fabric_io_regions(domain, &idx);
203 
204 	add_data_fabric_mmio_regions(domain, &idx);
205 
206 	read_non_pci_resources(domain, &idx);
207 
208 	/* Only add the SoC's DRAM memory map and fixed resources once */
209 	if (domain->path.domain.domain == 0) {
210 		add_pci_cfg_resources(domain, &idx);
211 
212 		read_soc_memmap_resources(domain, &idx);
213 	}
214 }
215