]>
Commit | Line | Data |
---|---|---|
5b85eabe GH |
1 | #include "qemu/osdep.h" |
2 | #include "hw/acpi/aml-build.h" | |
3 | #include "hw/pci-host/gpex.h" | |
6f9765fb YM |
4 | #include "hw/arm/virt.h" |
5 | #include "hw/pci/pci_bus.h" | |
6 | #include "hw/pci/pci_bridge.h" | |
7 | #include "hw/pci/pcie_host.h" | |
fc1e01e0 | 8 | #include "hw/acpi/cxl.h" |
5b85eabe | 9 | |
a0e2905b | 10 | static void acpi_dsdt_add_pci_route_table(Aml *dev, uint32_t irq) |
5b85eabe | 11 | { |
a0e2905b | 12 | Aml *method, *crs; |
5b85eabe GH |
13 | int i, slot_no; |
14 | ||
5b85eabe GH |
15 | /* Declare the PCI Routing Table. */ |
16 | Aml *rt_pkg = aml_varpackage(PCI_SLOT_MAX * PCI_NUM_PINS); | |
17 | for (slot_no = 0; slot_no < PCI_SLOT_MAX; slot_no++) { | |
18 | for (i = 0; i < PCI_NUM_PINS; i++) { | |
19 | int gsi = (i + slot_no) % PCI_NUM_PINS; | |
20 | Aml *pkg = aml_package(4); | |
21 | aml_append(pkg, aml_int((slot_no << 16) | 0xFFFF)); | |
22 | aml_append(pkg, aml_int(i)); | |
23 | aml_append(pkg, aml_name("GSI%d", gsi)); | |
24 | aml_append(pkg, aml_int(0)); | |
25 | aml_append(rt_pkg, pkg); | |
26 | } | |
27 | } | |
28 | aml_append(dev, aml_name_decl("_PRT", rt_pkg)); | |
29 | ||
30 | /* Create GSI link device */ | |
31 | for (i = 0; i < PCI_NUM_PINS; i++) { | |
a0e2905b | 32 | uint32_t irqs = irq + i; |
5b85eabe GH |
33 | Aml *dev_gsi = aml_device("GSI%d", i); |
34 | aml_append(dev_gsi, aml_name_decl("_HID", aml_string("PNP0C0F"))); | |
35 | aml_append(dev_gsi, aml_name_decl("_UID", aml_int(i))); | |
36 | crs = aml_resource_template(); | |
37 | aml_append(crs, | |
38 | aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, | |
39 | AML_EXCLUSIVE, &irqs, 1)); | |
40 | aml_append(dev_gsi, aml_name_decl("_PRS", crs)); | |
41 | crs = aml_resource_template(); | |
42 | aml_append(crs, | |
43 | aml_interrupt(AML_CONSUMER, AML_LEVEL, AML_ACTIVE_HIGH, | |
44 | AML_EXCLUSIVE, &irqs, 1)); | |
45 | aml_append(dev_gsi, aml_name_decl("_CRS", crs)); | |
46 | method = aml_method("_SRS", 1, AML_NOTSERIALIZED); | |
47 | aml_append(dev_gsi, method); | |
48 | aml_append(dev, dev_gsi); | |
49 | } | |
a0e2905b | 50 | } |
5b85eabe | 51 | |
a0e2905b YM |
52 | static void acpi_dsdt_add_pci_osc(Aml *dev) |
53 | { | |
54 | Aml *method, *UUID, *ifctx, *ifctx1, *elsectx, *buf; | |
5b85eabe GH |
55 | |
56 | /* Declare an _OSC (OS Control Handoff) method */ | |
57 | aml_append(dev, aml_name_decl("SUPP", aml_int(0))); | |
58 | aml_append(dev, aml_name_decl("CTRL", aml_int(0))); | |
59 | method = aml_method("_OSC", 4, AML_NOTSERIALIZED); | |
60 | aml_append(method, | |
61 | aml_create_dword_field(aml_arg(3), aml_int(0), "CDW1")); | |
62 | ||
63 | /* PCI Firmware Specification 3.0 | |
64 | * 4.5.1. _OSC Interface for PCI Host Bridge Devices | |
65 | * The _OSC interface for a PCI/PCI-X/PCI Express hierarchy is | |
66 | * identified by the Universal Unique IDentifier (UUID) | |
67 | * 33DB4D5B-1FF7-401C-9657-7441C03DD766 | |
68 | */ | |
69 | UUID = aml_touuid("33DB4D5B-1FF7-401C-9657-7441C03DD766"); | |
70 | ifctx = aml_if(aml_equal(aml_arg(0), UUID)); | |
71 | aml_append(ifctx, | |
72 | aml_create_dword_field(aml_arg(3), aml_int(4), "CDW2")); | |
73 | aml_append(ifctx, | |
74 | aml_create_dword_field(aml_arg(3), aml_int(8), "CDW3")); | |
75 | aml_append(ifctx, aml_store(aml_name("CDW2"), aml_name("SUPP"))); | |
76 | aml_append(ifctx, aml_store(aml_name("CDW3"), aml_name("CTRL"))); | |
77 | ||
78 | /* | |
79 | * Allow OS control for all 5 features: | |
80 | * PCIeHotplug SHPCHotplug PME AER PCIeCapability. | |
81 | */ | |
82 | aml_append(ifctx, aml_and(aml_name("CTRL"), aml_int(0x1F), | |
83 | aml_name("CTRL"))); | |
84 | ||
85 | ifctx1 = aml_if(aml_lnot(aml_equal(aml_arg(1), aml_int(0x1)))); | |
86 | aml_append(ifctx1, aml_or(aml_name("CDW1"), aml_int(0x08), | |
87 | aml_name("CDW1"))); | |
88 | aml_append(ifctx, ifctx1); | |
89 | ||
90 | ifctx1 = aml_if(aml_lnot(aml_equal(aml_name("CDW3"), aml_name("CTRL")))); | |
91 | aml_append(ifctx1, aml_or(aml_name("CDW1"), aml_int(0x10), | |
92 | aml_name("CDW1"))); | |
93 | aml_append(ifctx, ifctx1); | |
94 | ||
95 | aml_append(ifctx, aml_store(aml_name("CTRL"), aml_name("CDW3"))); | |
96 | aml_append(ifctx, aml_return(aml_arg(3))); | |
97 | aml_append(method, ifctx); | |
98 | ||
99 | elsectx = aml_else(); | |
100 | aml_append(elsectx, aml_or(aml_name("CDW1"), aml_int(4), | |
101 | aml_name("CDW1"))); | |
102 | aml_append(elsectx, aml_return(aml_arg(3))); | |
103 | aml_append(method, elsectx); | |
104 | aml_append(dev, method); | |
105 | ||
106 | method = aml_method("_DSM", 4, AML_NOTSERIALIZED); | |
107 | ||
108 | /* PCI Firmware Specification 3.0 | |
109 | * 4.6.1. _DSM for PCI Express Slot Information | |
110 | * The UUID in _DSM in this context is | |
111 | * {E5C937D0-3553-4D7A-9117-EA4D19C3434D} | |
112 | */ | |
113 | UUID = aml_touuid("E5C937D0-3553-4D7A-9117-EA4D19C3434D"); | |
114 | ifctx = aml_if(aml_equal(aml_arg(0), UUID)); | |
115 | ifctx1 = aml_if(aml_equal(aml_arg(2), aml_int(0))); | |
40c3472a MT |
116 | uint8_t byte_list[1] = {1}; |
117 | buf = aml_buffer(1, byte_list); | |
5b85eabe | 118 | aml_append(ifctx1, aml_return(buf)); |
0cf8882f | 119 | aml_append(ifctx, ifctx1); |
5b85eabe GH |
120 | aml_append(method, ifctx); |
121 | ||
122 | byte_list[0] = 0; | |
123 | buf = aml_buffer(1, byte_list); | |
124 | aml_append(method, aml_return(buf)); | |
125 | aml_append(dev, method); | |
a0e2905b YM |
126 | } |
127 | ||
128 | void acpi_dsdt_add_gpex(Aml *scope, struct GPEXConfig *cfg) | |
129 | { | |
130 | int nr_pcie_buses = cfg->ecam.size / PCIE_MMCFG_SIZE_MIN; | |
131 | Aml *method, *crs, *dev, *rbuf; | |
6f9765fb YM |
132 | PCIBus *bus = cfg->bus; |
133 | CrsRangeSet crs_range_set; | |
aee519c2 JC |
134 | CrsRangeEntry *entry; |
135 | int i; | |
6f9765fb YM |
136 | |
137 | /* start to construct the tables for pxb */ | |
138 | crs_range_set_init(&crs_range_set); | |
139 | if (bus) { | |
140 | QLIST_FOREACH(bus, &bus->child, sibling) { | |
141 | uint8_t bus_num = pci_bus_num(bus); | |
142 | uint8_t numa_node = pci_bus_numa_node(bus); | |
fc1e01e0 | 143 | bool is_cxl = pci_bus_is_cxl(bus); |
6f9765fb YM |
144 | |
145 | if (!pci_bus_is_root(bus)) { | |
146 | continue; | |
147 | } | |
148 | ||
149 | /* | |
150 | * 0 - (nr_pcie_buses - 1) is the bus range for the main | |
151 | * host-bridge and it equals the MIN of the | |
152 | * busNr defined for pxb-pcie. | |
153 | */ | |
154 | if (bus_num < nr_pcie_buses) { | |
155 | nr_pcie_buses = bus_num; | |
156 | } | |
157 | ||
158 | dev = aml_device("PC%.02X", bus_num); | |
fc1e01e0 JC |
159 | if (is_cxl) { |
160 | struct Aml *pkg = aml_package(2); | |
161 | aml_append(dev, aml_name_decl("_HID", aml_string("ACPI0016"))); | |
162 | aml_append(pkg, aml_eisaid("PNP0A08")); | |
163 | aml_append(pkg, aml_eisaid("PNP0A03")); | |
164 | aml_append(dev, aml_name_decl("_CID", pkg)); | |
165 | } else { | |
166 | aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A08"))); | |
167 | aml_append(dev, aml_name_decl("_CID", aml_string("PNP0A03"))); | |
168 | } | |
6f9765fb YM |
169 | aml_append(dev, aml_name_decl("_BBN", aml_int(bus_num))); |
170 | aml_append(dev, aml_name_decl("_UID", aml_int(bus_num))); | |
171 | aml_append(dev, aml_name_decl("_STR", aml_unicode("pxb Device"))); | |
b48088d6 | 172 | aml_append(dev, aml_name_decl("_CCA", aml_int(1))); |
6f9765fb YM |
173 | if (numa_node != NUMA_NODE_UNASSIGNED) { |
174 | aml_append(dev, aml_name_decl("_PXM", aml_int(numa_node))); | |
175 | } | |
176 | ||
177 | acpi_dsdt_add_pci_route_table(dev, cfg->irq); | |
178 | ||
179 | /* | |
180 | * Resources defined for PXBs are composed by the folling parts: | |
181 | * 1. The resources the pci-brige/pcie-root-port need. | |
182 | * 2. The resources the devices behind pxb need. | |
183 | */ | |
e41ee855 JC |
184 | crs = build_crs(PCI_HOST_BRIDGE(BUS(bus)->parent), &crs_range_set, |
185 | cfg->pio.base, 0, 0, 0); | |
6f9765fb YM |
186 | aml_append(dev, aml_name_decl("_CRS", crs)); |
187 | ||
fc1e01e0 JC |
188 | if (is_cxl) { |
189 | build_cxl_osc_method(dev); | |
190 | } else { | |
191 | acpi_dsdt_add_pci_osc(dev); | |
192 | } | |
6f9765fb YM |
193 | |
194 | aml_append(scope, dev); | |
195 | } | |
196 | } | |
a0e2905b | 197 | |
6f9765fb | 198 | /* tables for the main */ |
a0e2905b YM |
199 | dev = aml_device("%s", "PCI0"); |
200 | aml_append(dev, aml_name_decl("_HID", aml_string("PNP0A08"))); | |
201 | aml_append(dev, aml_name_decl("_CID", aml_string("PNP0A03"))); | |
202 | aml_append(dev, aml_name_decl("_SEG", aml_int(0))); | |
203 | aml_append(dev, aml_name_decl("_BBN", aml_int(0))); | |
204 | aml_append(dev, aml_name_decl("_UID", aml_int(0))); | |
205 | aml_append(dev, aml_name_decl("_STR", aml_unicode("PCIe 0 Device"))); | |
206 | aml_append(dev, aml_name_decl("_CCA", aml_int(1))); | |
207 | ||
208 | acpi_dsdt_add_pci_route_table(dev, cfg->irq); | |
209 | ||
210 | method = aml_method("_CBA", 0, AML_NOTSERIALIZED); | |
211 | aml_append(method, aml_return(aml_int(cfg->ecam.base))); | |
212 | aml_append(dev, method); | |
213 | ||
aee519c2 JC |
214 | /* |
215 | * At this point crs_range_set has all the ranges used by pci | |
216 | * busses *other* than PCI0. These ranges will be excluded from | |
217 | * the PCI0._CRS. | |
218 | */ | |
a0e2905b YM |
219 | rbuf = aml_resource_template(); |
220 | aml_append(rbuf, | |
221 | aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE, | |
222 | 0x0000, 0x0000, nr_pcie_buses - 1, 0x0000, | |
223 | nr_pcie_buses)); | |
224 | if (cfg->mmio32.size) { | |
aee519c2 JC |
225 | crs_replace_with_free_ranges(crs_range_set.mem_ranges, |
226 | cfg->mmio32.base, | |
227 | cfg->mmio32.base + cfg->mmio32.size - 1); | |
228 | for (i = 0; i < crs_range_set.mem_ranges->len; i++) { | |
229 | entry = g_ptr_array_index(crs_range_set.mem_ranges, i); | |
230 | aml_append(rbuf, | |
231 | aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, | |
232 | AML_NON_CACHEABLE, AML_READ_WRITE, 0x0000, | |
233 | entry->base, entry->limit, | |
234 | 0x0000, entry->limit - entry->base + 1)); | |
235 | } | |
a0e2905b YM |
236 | } |
237 | if (cfg->pio.size) { | |
aee519c2 JC |
238 | crs_replace_with_free_ranges(crs_range_set.io_ranges, |
239 | 0x0000, | |
240 | cfg->pio.size - 1); | |
241 | for (i = 0; i < crs_range_set.io_ranges->len; i++) { | |
242 | entry = g_ptr_array_index(crs_range_set.io_ranges, i); | |
243 | aml_append(rbuf, | |
244 | aml_dword_io(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE, | |
245 | AML_ENTIRE_RANGE, 0x0000, entry->base, | |
246 | entry->limit, cfg->pio.base, | |
247 | entry->limit - entry->base + 1)); | |
248 | } | |
a0e2905b YM |
249 | } |
250 | if (cfg->mmio64.size) { | |
aee519c2 JC |
251 | crs_replace_with_free_ranges(crs_range_set.mem_64bit_ranges, |
252 | cfg->mmio64.base, | |
253 | cfg->mmio64.base + cfg->mmio64.size - 1); | |
254 | for (i = 0; i < crs_range_set.mem_64bit_ranges->len; i++) { | |
255 | entry = g_ptr_array_index(crs_range_set.mem_64bit_ranges, i); | |
256 | aml_append(rbuf, | |
257 | aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, | |
258 | AML_NON_CACHEABLE, AML_READ_WRITE, 0x0000, | |
259 | entry->base, | |
260 | entry->limit, 0x0000, | |
261 | entry->limit - entry->base + 1)); | |
262 | } | |
a0e2905b YM |
263 | } |
264 | aml_append(dev, aml_name_decl("_CRS", rbuf)); | |
265 | ||
266 | acpi_dsdt_add_pci_osc(dev); | |
5b85eabe GH |
267 | |
268 | Aml *dev_res0 = aml_device("%s", "RES0"); | |
269 | aml_append(dev_res0, aml_name_decl("_HID", aml_string("PNP0C02"))); | |
270 | crs = aml_resource_template(); | |
271 | aml_append(crs, | |
272 | aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED, | |
273 | AML_NON_CACHEABLE, AML_READ_WRITE, 0x0000, | |
274 | cfg->ecam.base, | |
275 | cfg->ecam.base + cfg->ecam.size - 1, | |
276 | 0x0000, | |
277 | cfg->ecam.size)); | |
278 | aml_append(dev_res0, aml_name_decl("_CRS", crs)); | |
279 | aml_append(dev, dev_res0); | |
280 | aml_append(scope, dev); | |
aee519c2 JC |
281 | |
282 | crs_range_set_free(&crs_range_set); | |
5b85eabe | 283 | } |