blob: 67bca5592dc26e63ff776151a28f2862e7afd2a7 [file] [log] [blame]
Arthur Heymans92a3b672023-06-22 21:30:58 +02001/* SPDX-License-Identifier: GPL-2.0-only */
2
3#include <acpi/acpi.h>
4#include <arch/ioapic.h>
Shuo Liubcd24732024-06-25 19:04:11 +08005#include <assert.h>
Arthur Heymans92a3b672023-06-22 21:30:58 +02006#include <cpu/cpu.h>
Shuo Liubcd24732024-06-25 19:04:11 +08007#include <lib.h>
Arthur Heymans92a3b672023-06-22 21:30:58 +02008#include <version.h>
9
10void acpi_create_dmar(acpi_dmar_t *dmar, enum dmar_flags flags,
11 unsigned long (*acpi_fill_dmar)(unsigned long))
12{
13 acpi_header_t *header = &(dmar->header);
14 unsigned long current = (unsigned long)dmar + sizeof(acpi_dmar_t);
15
16 memset((void *)dmar, 0, sizeof(acpi_dmar_t));
17
18 if (!header)
19 return;
20
21 /* Fill out header fields. */
22 memcpy(header->signature, "DMAR", 4);
23 memcpy(header->oem_id, OEM_ID, 6);
24 memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
25 memcpy(header->asl_compiler_id, ASLC, 4);
26
27 header->asl_compiler_revision = asl_revision;
28 header->length = sizeof(acpi_dmar_t);
29 header->revision = get_acpi_table_revision(DMAR);
30
Jeremy Compostellaba757a72023-12-20 09:07:04 -080031 dmar->host_address_width = soc_phys_address_size() - 1;
Arthur Heymans92a3b672023-06-22 21:30:58 +020032 dmar->flags = flags;
33
34 current = acpi_fill_dmar(current);
35
36 /* (Re)calculate length and checksum. */
37 header->length = current - (unsigned long)dmar;
38 header->checksum = acpi_checksum((void *)dmar, header->length);
39}
40
Shuo Liuf3aaa0e2024-06-25 18:50:06 +080041unsigned long acpi_create_dmar_drhd_4k(unsigned long current, u8 flags,
Shuo Liubcd24732024-06-25 19:04:11 +080042 u16 segment, u64 bar)
Arthur Heymans92a3b672023-06-22 21:30:58 +020043{
Shuo Liubcd24732024-06-25 19:04:11 +080044 return acpi_create_dmar_drhd(current, flags, segment, bar, 4 * KiB);
45}
46
47unsigned long acpi_create_dmar_drhd(unsigned long current, u8 flags,
48 u16 segment, u64 bar, size_t size)
49{
50 /*
51 * Refer to IntelĀ® Virtualization Technology for Directed I/O
52 * Architecture Specification Revision 4.1,
53 * size is at least 1 page and max 2^15 pages, 4 KiB each, and the bar
54 * should be aligned with size.
55 */
56 assert(4 * KiB <= size && size <= (1 << 15) * 4 * KiB && IS_POWER_OF_2(size));
57 assert(IS_ALIGNED(bar, size));
58
Arthur Heymans92a3b672023-06-22 21:30:58 +020059 dmar_entry_t *drhd = (dmar_entry_t *)current;
60 memset(drhd, 0, sizeof(*drhd));
61 drhd->type = DMAR_DRHD;
62 drhd->length = sizeof(*drhd); /* will be fixed up later */
63 drhd->flags = flags;
64 drhd->segment = segment;
65 drhd->bar = bar;
Shuo Liubcd24732024-06-25 19:04:11 +080066 drhd->size = log2_64(size) - 12;
Arthur Heymans92a3b672023-06-22 21:30:58 +020067
68 return drhd->length;
69}
70
71unsigned long acpi_create_dmar_rmrr(unsigned long current, u16 segment,
72 u64 bar, u64 limit)
73{
74 dmar_rmrr_entry_t *rmrr = (dmar_rmrr_entry_t *)current;
75 memset(rmrr, 0, sizeof(*rmrr));
76 rmrr->type = DMAR_RMRR;
77 rmrr->length = sizeof(*rmrr); /* will be fixed up later */
78 rmrr->segment = segment;
79 rmrr->bar = bar;
80 rmrr->limit = limit;
81
82 return rmrr->length;
83}
84
85unsigned long acpi_create_dmar_atsr(unsigned long current, u8 flags,
86 u16 segment)
87{
88 dmar_atsr_entry_t *atsr = (dmar_atsr_entry_t *)current;
89 memset(atsr, 0, sizeof(*atsr));
90 atsr->type = DMAR_ATSR;
91 atsr->length = sizeof(*atsr); /* will be fixed up later */
92 atsr->flags = flags;
93 atsr->segment = segment;
94
95 return atsr->length;
96}
97
98unsigned long acpi_create_dmar_rhsa(unsigned long current, u64 base_addr,
99 u32 proximity_domain)
100{
101 dmar_rhsa_entry_t *rhsa = (dmar_rhsa_entry_t *)current;
102 memset(rhsa, 0, sizeof(*rhsa));
103 rhsa->type = DMAR_RHSA;
104 rhsa->length = sizeof(*rhsa);
105 rhsa->base_address = base_addr;
106 rhsa->proximity_domain = proximity_domain;
107
108 return rhsa->length;
109}
110
111unsigned long acpi_create_dmar_andd(unsigned long current, u8 device_number,
112 const char *device_name)
113{
114 dmar_andd_entry_t *andd = (dmar_andd_entry_t *)current;
115 int andd_len = sizeof(dmar_andd_entry_t) + strlen(device_name) + 1;
116 memset(andd, 0, andd_len);
117 andd->type = DMAR_ANDD;
118 andd->length = andd_len;
119 andd->device_number = device_number;
120 memcpy(&andd->device_name, device_name, strlen(device_name));
121
122 return andd->length;
123}
124
125unsigned long acpi_create_dmar_satc(unsigned long current, u8 flags, u16 segment)
126{
127 dmar_satc_entry_t *satc = (dmar_satc_entry_t *)current;
128 int satc_len = sizeof(dmar_satc_entry_t);
129 memset(satc, 0, satc_len);
130 satc->type = DMAR_SATC;
131 satc->length = satc_len;
132 satc->flags = flags;
133 satc->segment_number = segment;
134
135 return satc->length;
136}
137
138void acpi_dmar_drhd_fixup(unsigned long base, unsigned long current)
139{
140 dmar_entry_t *drhd = (dmar_entry_t *)base;
141 drhd->length = current - base;
142}
143
144void acpi_dmar_rmrr_fixup(unsigned long base, unsigned long current)
145{
146 dmar_rmrr_entry_t *rmrr = (dmar_rmrr_entry_t *)base;
147 rmrr->length = current - base;
148}
149
150void acpi_dmar_atsr_fixup(unsigned long base, unsigned long current)
151{
152 dmar_atsr_entry_t *atsr = (dmar_atsr_entry_t *)base;
153 atsr->length = current - base;
154}
155
156void acpi_dmar_satc_fixup(unsigned long base, unsigned long current)
157{
158 dmar_satc_entry_t *satc = (dmar_satc_entry_t *)base;
159 satc->length = current - base;
160}
161
162static unsigned long acpi_create_dmar_ds(unsigned long current,
163 enum dev_scope_type type, u8 enumeration_id, u8 bus, u8 dev, u8 fn)
164{
165 /* we don't support longer paths yet */
166 const size_t dev_scope_length = sizeof(dev_scope_t) + 2;
167
168 dev_scope_t *ds = (dev_scope_t *)current;
169 memset(ds, 0, dev_scope_length);
170 ds->type = type;
171 ds->length = dev_scope_length;
172 ds->enumeration = enumeration_id;
173 ds->start_bus = bus;
174 ds->path[0].dev = dev;
175 ds->path[0].fn = fn;
176
177 return ds->length;
178}
179
180unsigned long acpi_create_dmar_ds_pci_br(unsigned long current, u8 bus,
181 u8 dev, u8 fn)
182{
183 return acpi_create_dmar_ds(current,
184 SCOPE_PCI_SUB, 0, bus, dev, fn);
185}
186
187unsigned long acpi_create_dmar_ds_pci(unsigned long current, u8 bus,
188 u8 dev, u8 fn)
189{
190 return acpi_create_dmar_ds(current,
191 SCOPE_PCI_ENDPOINT, 0, bus, dev, fn);
192}
193
194unsigned long acpi_create_dmar_ds_ioapic(unsigned long current,
195 u8 enumeration_id, u8 bus, u8 dev, u8 fn)
196{
197 return acpi_create_dmar_ds(current,
198 SCOPE_IOAPIC, enumeration_id, bus, dev, fn);
199}
200
201unsigned long acpi_create_dmar_ds_ioapic_from_hw(unsigned long current,
202 u32 addr, u8 bus, u8 dev, u8 fn)
203{
Felix Held0d192892024-02-06 16:55:29 +0100204 u8 enumeration_id = get_ioapic_id((uintptr_t)addr);
Arthur Heymans92a3b672023-06-22 21:30:58 +0200205 return acpi_create_dmar_ds(current,
206 SCOPE_IOAPIC, enumeration_id, bus, dev, fn);
207}
208
209unsigned long acpi_create_dmar_ds_msi_hpet(unsigned long current,
210 u8 enumeration_id, u8 bus, u8 dev, u8 fn)
211{
212 return acpi_create_dmar_ds(current,
213 SCOPE_MSI_HPET, enumeration_id, bus, dev, fn);
214}