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