1 /* SPDX-License-Identifier: GPL-2.0-only */
4 #include <arch/ioapic.h>
10 void acpi_create_dmar(acpi_dmar_t
*dmar
, enum dmar_flags flags
,
11 unsigned long (*acpi_fill_dmar
)(unsigned long))
13 acpi_header_t
*header
= &(dmar
->header
);
14 unsigned long current
= (unsigned long)dmar
+ sizeof(acpi_dmar_t
);
16 memset((void *)dmar
, 0, sizeof(acpi_dmar_t
));
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);
27 header
->asl_compiler_revision
= asl_revision
;
28 header
->length
= sizeof(acpi_dmar_t
);
29 header
->revision
= get_acpi_table_revision(DMAR
);
31 dmar
->host_address_width
= soc_phys_address_size() - 1;
34 current
= acpi_fill_dmar(current
);
36 /* (Re)calculate length and checksum. */
37 header
->length
= current
- (unsigned long)dmar
;
38 header
->checksum
= acpi_checksum((void *)dmar
, header
->length
);
41 unsigned long acpi_create_dmar_drhd_4k(unsigned long current
, u8 flags
,
44 return acpi_create_dmar_drhd(current
, flags
, segment
, bar
, 4 * KiB
);
47 unsigned long acpi_create_dmar_drhd(unsigned long current
, u8 flags
,
48 u16 segment
, u64 bar
, size_t size
)
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.
56 assert(4 * KiB
<= size
&& size
<= (1 << 15) * 4 * KiB
&& IS_POWER_OF_2(size
));
57 assert(IS_ALIGNED(bar
, size
));
59 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 */
64 drhd
->segment
= segment
;
66 drhd
->size
= log2_64(size
) - 12;
71 unsigned long acpi_create_dmar_rmrr(unsigned long current
, u16 segment
,
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
;
85 unsigned long acpi_create_dmar_atsr(unsigned long current
, u8 flags
,
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 */
93 atsr
->segment
= segment
;
98 unsigned long acpi_create_dmar_rhsa(unsigned long current
, u64 base_addr
,
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
;
111 unsigned long acpi_create_dmar_andd(unsigned long current
, u8 device_number
,
112 const char *device_name
)
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
));
125 unsigned long acpi_create_dmar_satc(unsigned long current
, u8 flags
, u16 segment
)
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
;
133 satc
->segment_number
= segment
;
138 void acpi_dmar_drhd_fixup(unsigned long base
, unsigned long current
)
140 dmar_entry_t
*drhd
= (dmar_entry_t
*)base
;
141 drhd
->length
= current
- base
;
144 void acpi_dmar_rmrr_fixup(unsigned long base
, unsigned long current
)
146 dmar_rmrr_entry_t
*rmrr
= (dmar_rmrr_entry_t
*)base
;
147 rmrr
->length
= current
- base
;
150 void acpi_dmar_atsr_fixup(unsigned long base
, unsigned long current
)
152 dmar_atsr_entry_t
*atsr
= (dmar_atsr_entry_t
*)base
;
153 atsr
->length
= current
- base
;
156 void acpi_dmar_satc_fixup(unsigned long base
, unsigned long current
)
158 dmar_satc_entry_t
*satc
= (dmar_satc_entry_t
*)base
;
159 satc
->length
= current
- base
;
162 static unsigned long acpi_create_dmar_ds(unsigned long current
,
163 enum dev_scope_type type
, u8 enumeration_id
, u8 bus
, u8 dev
, u8 fn
)
165 /* we don't support longer paths yet */
166 const size_t dev_scope_length
= sizeof(dev_scope_t
) + 2;
168 dev_scope_t
*ds
= (dev_scope_t
*)current
;
169 memset(ds
, 0, dev_scope_length
);
171 ds
->length
= dev_scope_length
;
172 ds
->enumeration
= enumeration_id
;
174 ds
->path
[0].dev
= dev
;
180 unsigned long acpi_create_dmar_ds_pci_br(unsigned long current
, u8 bus
,
183 return acpi_create_dmar_ds(current
,
184 SCOPE_PCI_SUB
, 0, bus
, dev
, fn
);
187 unsigned long acpi_create_dmar_ds_pci(unsigned long current
, u8 bus
,
190 return acpi_create_dmar_ds(current
,
191 SCOPE_PCI_ENDPOINT
, 0, bus
, dev
, fn
);
194 unsigned long acpi_create_dmar_ds_ioapic(unsigned long current
,
195 u8 enumeration_id
, u8 bus
, u8 dev
, u8 fn
)
197 return acpi_create_dmar_ds(current
,
198 SCOPE_IOAPIC
, enumeration_id
, bus
, dev
, fn
);
201 unsigned long acpi_create_dmar_ds_ioapic_from_hw(unsigned long current
,
202 u32 addr
, u8 bus
, u8 dev
, u8 fn
)
204 u8 enumeration_id
= get_ioapic_id((uintptr_t)addr
);
205 return acpi_create_dmar_ds(current
,
206 SCOPE_IOAPIC
, enumeration_id
, bus
, dev
, fn
);
209 unsigned long acpi_create_dmar_ds_msi_hpet(unsigned long current
,
210 u8 enumeration_id
, u8 bus
, u8 dev
, u8 fn
)
212 return acpi_create_dmar_ds(current
,
213 SCOPE_MSI_HPET
, enumeration_id
, bus
, dev
, fn
);