blob: 6473d95c1028d6e92588be8fc57eb50861cc36e1 [file] [log] [blame]
Simon Glass91fe8b72020-04-08 16:57:38 -06001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Generic code used to generate ACPI tables
4 *
5 * Copyright 2019 Google LLC
6 */
7
Patrick Rudolphf570ab62024-10-23 15:19:57 +02008#include <bloblist.h>
Simon Glassbfeb5d42020-04-08 16:57:39 -06009#include <cpu.h>
Patrick Rudolphf570ab62024-10-23 15:19:57 +020010#include <dm.h>
11#include <efi_api.h>
12#include <efi_loader.h>
Simon Glassf7ae49f2020-05-10 11:40:05 -060013#include <log.h>
Simon Glass29b35112020-04-26 09:19:50 -060014#include <mapmem.h>
15#include <tables_csum.h>
Maximilian Brune1c03efc2024-10-23 15:19:44 +020016#include <serial.h>
Simon Glass1e4d9652023-04-29 19:21:46 -060017#include <version_string.h>
Simon Glass86e17782020-04-26 09:19:47 -060018#include <acpi/acpi_table.h>
Maximilian Brune1c03efc2024-10-23 15:19:44 +020019#include <acpi/acpi_device.h>
Simon Glass401d1c42020-10-30 21:38:53 -060020#include <asm/global_data.h>
Simon Glass86e17782020-04-26 09:19:47 -060021#include <dm/acpi.h>
Patrick Rudolphf570ab62024-10-23 15:19:57 +020022#include <linux/sizes.h>
23#include <linux/log2.h>
24
25enum {
26 TABLE_SIZE = SZ_64K,
27};
28
29DECLARE_GLOBAL_DATA_PTR;
Simon Glassbfeb5d42020-04-08 16:57:39 -060030
Pali Rohára3423b32021-07-10 13:10:01 +020031/*
32 * OEM_REVISION is 32-bit unsigned number. It should be increased only when
33 * changing software version. Therefore it should not depend on build time.
34 * U-Boot calculates it from U-Boot version and represent it in hexadecimal
35 * notation. As U-Boot version is in form year.month set low 8 bits to 0x01
36 * to have valid date. So for U-Boot version 2021.04 OEM_REVISION is set to
37 * value 0x20210401.
38 */
Simon Glass1e4d9652023-04-29 19:21:46 -060039#define OEM_REVISION ((((version_num / 1000) % 10) << 28) | \
40 (((version_num / 100) % 10) << 24) | \
41 (((version_num / 10) % 10) << 20) | \
42 ((version_num % 10) << 16) | \
43 (((version_num_patch / 10) % 10) << 12) | \
44 ((version_num_patch % 10) << 8) | \
Pali Rohára3423b32021-07-10 13:10:01 +020045 0x01)
46
Simon Glassbfeb5d42020-04-08 16:57:39 -060047int acpi_create_dmar(struct acpi_dmar *dmar, enum dmar_flags flags)
48{
49 struct acpi_table_header *header = &dmar->header;
50 struct cpu_info info;
51 struct udevice *cpu;
52 int ret;
53
Michal Suchanekc726fc02022-10-12 21:57:59 +020054 ret = uclass_first_device_err(UCLASS_CPU, &cpu);
Simon Glassbfeb5d42020-04-08 16:57:39 -060055 if (ret)
56 return log_msg_ret("cpu", ret);
57 ret = cpu_get_info(cpu, &info);
58 if (ret)
59 return log_msg_ret("info", ret);
60 memset((void *)dmar, 0, sizeof(struct acpi_dmar));
61
62 /* Fill out header fields. */
63 acpi_fill_header(&dmar->header, "DMAR");
64 header->length = sizeof(struct acpi_dmar);
65 header->revision = acpi_get_table_revision(ACPITAB_DMAR);
66
67 dmar->host_address_width = info.address_width - 1;
68 dmar->flags = flags;
69
70 return 0;
71}
Simon Glass91fe8b72020-04-08 16:57:38 -060072
73int acpi_get_table_revision(enum acpi_tables table)
74{
75 switch (table) {
76 case ACPITAB_FADT:
Patrick Rudolph4b882f62024-10-23 15:19:52 +020077 return ACPI_FADT_REV_ACPI_6_0;
Simon Glass91fe8b72020-04-08 16:57:38 -060078 case ACPITAB_MADT:
Patrick Rudolph4b882f62024-10-23 15:19:52 +020079 return ACPI_MADT_REV_ACPI_6_2;
Simon Glass91fe8b72020-04-08 16:57:38 -060080 case ACPITAB_MCFG:
81 return ACPI_MCFG_REV_ACPI_3_0;
82 case ACPITAB_TCPA:
83 /* This version and the rest are open-coded */
84 return 2;
85 case ACPITAB_TPM2:
86 return 4;
87 case ACPITAB_SSDT: /* ACPI 3.0 upto 6.3: 2 */
88 return 2;
89 case ACPITAB_SRAT: /* ACPI 2.0: 1, ACPI 3.0: 2, ACPI 4.0 to 6.3: 3 */
90 return 1; /* TODO Should probably be upgraded to 2 */
91 case ACPITAB_DMAR:
92 return 1;
93 case ACPITAB_SLIT: /* ACPI 2.0 upto 6.3: 1 */
94 return 1;
95 case ACPITAB_SPMI: /* IMPI 2.0 */
96 return 5;
97 case ACPITAB_HPET: /* Currently 1. Table added in ACPI 2.0 */
98 return 1;
99 case ACPITAB_VFCT: /* ACPI 2.0/3.0/4.0: 1 */
100 return 1;
101 case ACPITAB_IVRS:
102 return IVRS_FORMAT_FIXED;
103 case ACPITAB_DBG2:
104 return 0;
105 case ACPITAB_FACS: /* ACPI 2.0/3.0: 1, ACPI 4.0 to 6.3: 2 */
106 return 1;
107 case ACPITAB_RSDT: /* ACPI 1.0 upto 6.3: 1 */
108 return 1;
109 case ACPITAB_XSDT: /* ACPI 2.0 upto 6.3: 1 */
110 return 1;
111 case ACPITAB_RSDP: /* ACPI 2.0 upto 6.3: 2 */
112 return 2;
113 case ACPITAB_HEST:
114 return 1;
115 case ACPITAB_NHLT:
116 return 5;
117 case ACPITAB_BERT:
118 return 1;
119 case ACPITAB_SPCR:
120 return 2;
Patrick Rudolph7f91bca2024-10-23 15:19:53 +0200121 case ACPITAB_PPTT: /* ACPI 6.2: 1 */
122 return 1;
123 case ACPITAB_GTDT: /* ACPI 6.2: 2, ACPI 6.3: 3 */
124 return 2;
Simon Glass91fe8b72020-04-08 16:57:38 -0600125 default:
126 return -EINVAL;
127 }
128}
Simon Glass93f7f822020-04-26 09:19:46 -0600129
130void acpi_fill_header(struct acpi_table_header *header, char *signature)
131{
132 memcpy(header->signature, signature, 4);
133 memcpy(header->oem_id, OEM_ID, 6);
134 memcpy(header->oem_table_id, OEM_TABLE_ID, 8);
Pali Rohára3423b32021-07-10 13:10:01 +0200135 header->oem_revision = OEM_REVISION;
Heinrich Schuchardt4735d032024-01-21 12:52:48 +0100136 memcpy(header->creator_id, ASLC_ID, 4);
Heinrich Schuchardt07a6c692024-04-18 05:11:13 +0200137 header->creator_revision = ASL_REVISION;
Simon Glass93f7f822020-04-26 09:19:46 -0600138}
Simon Glass86e17782020-04-26 09:19:47 -0600139
140void acpi_align(struct acpi_ctx *ctx)
141{
142 ctx->current = (void *)ALIGN((ulong)ctx->current, 16);
143}
144
145void acpi_align64(struct acpi_ctx *ctx)
146{
147 ctx->current = (void *)ALIGN((ulong)ctx->current, 64);
148}
149
150void acpi_inc(struct acpi_ctx *ctx, uint amount)
151{
152 ctx->current += amount;
153}
154
155void acpi_inc_align(struct acpi_ctx *ctx, uint amount)
156{
157 ctx->current += amount;
158 acpi_align(ctx);
159}
Simon Glass29b35112020-04-26 09:19:50 -0600160
161/**
162 * Add an ACPI table to the RSDT (and XSDT) structure, recalculate length
163 * and checksum.
164 */
165int acpi_add_table(struct acpi_ctx *ctx, void *table)
166{
167 int i, entries_num;
168 struct acpi_rsdt *rsdt;
169 struct acpi_xsdt *xsdt;
170
Patrick Rudolph5dc22f72024-10-23 15:19:56 +0200171 /* On legacy x86 platforms the RSDT is mandatory while the XSDT is not.
172 * On other platforms there might be no memory below 4GiB, thus RSDT is NULL.
Simon Glass29b35112020-04-26 09:19:50 -0600173 */
Patrick Rudolph5dc22f72024-10-23 15:19:56 +0200174 if (ctx->rsdt) {
175 rsdt = ctx->rsdt;
Simon Glass29b35112020-04-26 09:19:50 -0600176
Patrick Rudolph5dc22f72024-10-23 15:19:56 +0200177 /* This should always be MAX_ACPI_TABLES */
178 entries_num = ARRAY_SIZE(rsdt->entry);
Simon Glass29b35112020-04-26 09:19:50 -0600179
Patrick Rudolph5dc22f72024-10-23 15:19:56 +0200180 for (i = 0; i < entries_num; i++) {
181 if (rsdt->entry[i] == 0)
182 break;
183 }
Simon Glass29b35112020-04-26 09:19:50 -0600184
Patrick Rudolph5dc22f72024-10-23 15:19:56 +0200185 if (i >= entries_num) {
186 log_err("ACPI: Error: too many tables\n");
187 return -E2BIG;
188 }
189
190 /* Add table to the RSDT */
191 rsdt->entry[i] = nomap_to_sysmem(table);
192
193 /* Fix RSDT length or the kernel will assume invalid entries */
194 rsdt->header.length = sizeof(struct acpi_table_header) +
195 (sizeof(u32) * (i + 1));
196
197 /* Re-calculate checksum */
198 rsdt->header.checksum = 0;
199 rsdt->header.checksum = table_compute_checksum((u8 *)rsdt,
200 rsdt->header.length);
201 }
202
203 if (ctx->xsdt) {
204 /*
205 * And now the same thing for the XSDT. We use the same index as for
206 * now we want the XSDT and RSDT to always be in sync in U-Boot
207 */
208 xsdt = ctx->xsdt;
209
210 /* This should always be MAX_ACPI_TABLES */
211 entries_num = ARRAY_SIZE(xsdt->entry);
212
213 for (i = 0; i < entries_num; i++) {
214 if (xsdt->entry[i] == 0)
215 break;
216 }
217
218 if (i >= entries_num) {
219 log_err("ACPI: Error: too many tables\n");
220 return -E2BIG;
221 }
222
223 /* Add table to the XSDT */
224 xsdt->entry[i] = nomap_to_sysmem(table);
225
226 /* Fix XSDT length */
227 xsdt->header.length = sizeof(struct acpi_table_header) +
228 (sizeof(u64) * (i + 1));
229
230 /* Re-calculate checksum */
231 xsdt->header.checksum = 0;
232 xsdt->header.checksum = table_compute_checksum((u8 *)xsdt,
233 xsdt->header.length);
234 }
Simon Glass29b35112020-04-26 09:19:50 -0600235
236 return 0;
237}
Simon Glass7e586f62020-04-26 09:19:51 -0600238
Maximilian Brunef5f79622024-10-23 15:19:45 +0200239int acpi_write_fadt(struct acpi_ctx *ctx, const struct acpi_writer *entry)
240{
241 struct acpi_table_header *header;
242 struct acpi_fadt *fadt;
243
244 fadt = ctx->current;
245 header = &fadt->header;
246
247 memset((void *)fadt, '\0', sizeof(struct acpi_fadt));
248
249 acpi_fill_header(header, "FACP");
250 header->length = sizeof(struct acpi_fadt);
251 header->revision = acpi_get_table_revision(ACPITAB_FADT);
252 memcpy(header->oem_id, OEM_ID, 6);
253 memcpy(header->oem_table_id, OEM_TABLE_ID, 8);
254 memcpy(header->creator_id, ASLC_ID, 4);
255 header->creator_revision = 1;
Patrick Rudolph4b882f62024-10-23 15:19:52 +0200256 fadt->minor_revision = 2;
Maximilian Brunef5f79622024-10-23 15:19:45 +0200257
258 fadt->x_firmware_ctrl = map_to_sysmem(ctx->facs);
259 fadt->x_dsdt = map_to_sysmem(ctx->dsdt);
260
261 if (fadt->x_firmware_ctrl < 0x100000000ULL)
262 fadt->firmware_ctrl = fadt->x_firmware_ctrl;
263
264 if (fadt->x_dsdt < 0x100000000ULL)
265 fadt->dsdt = fadt->x_dsdt;
266
267 fadt->preferred_pm_profile = ACPI_PM_UNSPECIFIED;
268
269 acpi_fill_fadt(fadt);
270
271 header->checksum = table_compute_checksum(fadt, header->length);
272
273 return acpi_add_fadt(ctx, fadt);
274}
275
276ACPI_WRITER(5fadt, "FADT", acpi_write_fadt, 0);
277
Patrick Rudolph4a3fc0f2024-10-23 15:19:46 +0200278int acpi_write_madt(struct acpi_ctx *ctx, const struct acpi_writer *entry)
279{
280 struct acpi_table_header *header;
281 struct acpi_madt *madt;
282 void *current;
283
284 madt = ctx->current;
285
286 memset(madt, '\0', sizeof(struct acpi_madt));
287 header = &madt->header;
288
289 /* Fill out header fields */
290 acpi_fill_header(header, "APIC");
291 header->length = sizeof(struct acpi_madt);
Patrick Rudolph4b882f62024-10-23 15:19:52 +0200292 header->revision = acpi_get_table_revision(ACPITAB_MADT);
Patrick Rudolph4a3fc0f2024-10-23 15:19:46 +0200293
294 acpi_inc(ctx, sizeof(struct acpi_madt));
Patrick Rudolph763bad32024-10-23 15:19:51 +0200295 /* TODO: Get rid of acpi_fill_madt and use driver model */
Patrick Rudolph4a3fc0f2024-10-23 15:19:46 +0200296 current = acpi_fill_madt(madt, ctx);
297
298 /* (Re)calculate length and checksum */
299 header->length = (uintptr_t)current - (uintptr_t)madt;
Patrick Rudolph34bfe8e2024-10-23 15:20:13 +0200300
301 if (IS_ENABLED(CONFIG_ACPI_PARKING_PROTOCOL))
302 acpi_write_park(madt);
303
Patrick Rudolph4a3fc0f2024-10-23 15:19:46 +0200304 header->checksum = table_compute_checksum((void *)madt, header->length);
305 acpi_add_table(ctx, madt);
306 ctx->current = (void *)madt + madt->header.length;
307
308 return 0;
309}
310
311ACPI_WRITER(5madt, "MADT", acpi_write_madt, 0);
312
Simon Glassf37979e2020-09-22 12:45:10 -0600313void acpi_create_dbg2(struct acpi_dbg2_header *dbg2,
314 int port_type, int port_subtype,
315 struct acpi_gen_regaddr *address, u32 address_size,
316 const char *device_path)
317{
318 uintptr_t current;
319 struct acpi_dbg2_device *device;
320 u32 *dbg2_addr_size;
321 struct acpi_table_header *header;
322 size_t path_len;
323 const char *path;
324 char *namespace;
325
326 /* Fill out header fields. */
327 current = (uintptr_t)dbg2;
328 memset(dbg2, '\0', sizeof(struct acpi_dbg2_header));
329 header = &dbg2->header;
330
331 header->revision = acpi_get_table_revision(ACPITAB_DBG2);
332 acpi_fill_header(header, "DBG2");
Simon Glassf37979e2020-09-22 12:45:10 -0600333
334 /* One debug device defined */
335 dbg2->devices_offset = sizeof(struct acpi_dbg2_header);
336 dbg2->devices_count = 1;
337 current += sizeof(struct acpi_dbg2_header);
338
339 /* Device comes after the header */
340 device = (struct acpi_dbg2_device *)current;
341 memset(device, 0, sizeof(struct acpi_dbg2_device));
342 current += sizeof(struct acpi_dbg2_device);
343
344 device->revision = 0;
345 device->address_count = 1;
346 device->port_type = port_type;
347 device->port_subtype = port_subtype;
348
349 /* Base Address comes after device structure */
350 memcpy((void *)current, address, sizeof(struct acpi_gen_regaddr));
351 device->base_address_offset = current - (uintptr_t)device;
352 current += sizeof(struct acpi_gen_regaddr);
353
354 /* Address Size comes after address structure */
355 dbg2_addr_size = (uint32_t *)current;
356 device->address_size_offset = current - (uintptr_t)device;
357 *dbg2_addr_size = address_size;
358 current += sizeof(uint32_t);
359
360 /* Namespace string comes last, use '.' if not provided */
361 path = device_path ? : ".";
362 /* Namespace string length includes NULL terminator */
363 path_len = strlen(path) + 1;
364 namespace = (char *)current;
365 device->namespace_string_length = path_len;
366 device->namespace_string_offset = current - (uintptr_t)device;
367 strncpy(namespace, path, path_len);
368 current += path_len;
369
370 /* Update structure lengths and checksum */
371 device->length = current - (uintptr_t)device;
372 header->length = current - (uintptr_t)dbg2;
373 header->checksum = table_compute_checksum(dbg2, header->length);
374}
Maximilian Brune1c03efc2024-10-23 15:19:44 +0200375
376int acpi_write_dbg2_pci_uart(struct acpi_ctx *ctx, struct udevice *dev,
377 uint access_size)
378{
379 struct acpi_dbg2_header *dbg2 = ctx->current;
380 char path[ACPI_PATH_MAX];
381 struct acpi_gen_regaddr address;
382 u64 addr;
383 int ret;
384
385 if (!device_active(dev)) {
386 log_info("Device not enabled\n");
387 return -EACCES;
388 }
389 /*
390 * PCI devices don't remember their resource allocation information in
391 * U-Boot at present. We assume that MMIO is used for the UART and that
392 * the address space is 32 bytes: ns16550 uses 8 registers of up to
393 * 32-bits each. This is only for debugging so it is not a big deal.
394 */
395 addr = dm_pci_read_bar32(dev, 0);
396 log_debug("UART addr %lx\n", (ulong)addr);
397
398 ret = acpi_device_path(dev, path, sizeof(path));
399 if (ret)
400 return log_msg_ret("path", ret);
401
402 memset(&address, '\0', sizeof(address));
403 address.space_id = ACPI_ADDRESS_SPACE_MEMORY;
404 address.addrl = (uint32_t)addr;
405 address.addrh = (uint32_t)((addr >> 32) & 0xffffffff);
406 address.access_size = access_size;
407
408 ret = acpi_device_path(dev, path, sizeof(path));
409 if (ret)
410 return log_msg_ret("path", ret);
411 acpi_create_dbg2(dbg2, ACPI_DBG2_SERIAL_PORT,
412 ACPI_DBG2_16550_COMPATIBLE, &address, 0x1000, path);
413
414 acpi_inc_align(ctx, dbg2->header.length);
415 acpi_add_table(ctx, dbg2);
416
417 return 0;
418}
419
420static int acpi_write_spcr(struct acpi_ctx *ctx, const struct acpi_writer *entry)
421{
422 struct serial_device_info serial_info = {0};
423 ulong serial_address, serial_offset;
424 struct acpi_table_header *header;
425 struct acpi_spcr *spcr;
426 struct udevice *dev;
427 uint serial_config;
428 uint serial_width;
429 int access_size;
430 int space_id;
431 int ret = -ENODEV;
432
433 spcr = ctx->current;
434 header = &spcr->header;
435
436 memset(spcr, '\0', sizeof(struct acpi_spcr));
437
438 /* Fill out header fields */
439 acpi_fill_header(header, "SPCR");
440 header->length = sizeof(struct acpi_spcr);
441 header->revision = 2;
442
443 /* Read the device once, here. It is reused below */
444 dev = gd->cur_serial_dev;
445 if (dev)
446 ret = serial_getinfo(dev, &serial_info);
447 if (ret)
448 serial_info.type = SERIAL_CHIP_UNKNOWN;
449
450 /* Encode chip type */
451 switch (serial_info.type) {
452 case SERIAL_CHIP_16550_COMPATIBLE:
453 spcr->interface_type = ACPI_DBG2_16550_COMPATIBLE;
454 break;
455 case SERIAL_CHIP_PL01X:
456 spcr->interface_type = ACPI_DBG2_ARM_PL011;
457 break;
458 case SERIAL_CHIP_UNKNOWN:
459 default:
460 spcr->interface_type = ACPI_DBG2_UNKNOWN;
461 break;
462 }
463
464 /* Encode address space */
465 switch (serial_info.addr_space) {
466 case SERIAL_ADDRESS_SPACE_MEMORY:
467 space_id = ACPI_ADDRESS_SPACE_MEMORY;
468 break;
469 case SERIAL_ADDRESS_SPACE_IO:
470 default:
471 space_id = ACPI_ADDRESS_SPACE_IO;
472 break;
473 }
474
475 serial_width = serial_info.reg_width * 8;
476 serial_offset = serial_info.reg_offset << serial_info.reg_shift;
477 serial_address = serial_info.addr + serial_offset;
478
479 /* Encode register access size */
480 switch (serial_info.reg_shift) {
481 case 0:
482 access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
483 break;
484 case 1:
485 access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
486 break;
487 case 2:
488 access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
489 break;
490 case 3:
491 access_size = ACPI_ACCESS_SIZE_QWORD_ACCESS;
492 break;
493 default:
494 access_size = ACPI_ACCESS_SIZE_UNDEFINED;
495 break;
496 }
497
498 debug("UART type %u @ %lx\n", spcr->interface_type, serial_address);
499
500 /* Fill GAS */
501 spcr->serial_port.space_id = space_id;
502 spcr->serial_port.bit_width = serial_width;
503 spcr->serial_port.bit_offset = 0;
504 spcr->serial_port.access_size = access_size;
505 spcr->serial_port.addrl = lower_32_bits(serial_address);
506 spcr->serial_port.addrh = upper_32_bits(serial_address);
507
508 /* Encode baud rate */
509 switch (serial_info.baudrate) {
510 case 9600:
511 spcr->baud_rate = 3;
512 break;
513 case 19200:
514 spcr->baud_rate = 4;
515 break;
516 case 57600:
517 spcr->baud_rate = 6;
518 break;
519 case 115200:
520 spcr->baud_rate = 7;
521 break;
522 default:
523 spcr->baud_rate = 0;
524 break;
525 }
526
527 serial_config = SERIAL_DEFAULT_CONFIG;
528 if (dev)
529 ret = serial_getconfig(dev, &serial_config);
530
531 spcr->parity = SERIAL_GET_PARITY(serial_config);
532 spcr->stop_bits = SERIAL_GET_STOP(serial_config);
533
534 /* No PCI devices for now */
535 spcr->pci_device_id = 0xffff;
536 spcr->pci_vendor_id = 0xffff;
537
538 /*
539 * SPCR has no clue if the UART base clock speed is different
540 * to the default one. However, the SPCR 1.04 defines baud rate
541 * 0 as a preconfigured state of UART and OS is supposed not
542 * to touch the configuration of the serial device.
543 */
544 if (serial_info.clock != SERIAL_DEFAULT_CLOCK)
545 spcr->baud_rate = 0;
546
547 /* Fix checksum */
548 header->checksum = table_compute_checksum((void *)spcr, header->length);
549
550 acpi_add_table(ctx, spcr);
551 acpi_inc(ctx, spcr->header.length);
552
553 return 0;
554}
555
556ACPI_WRITER(5spcr, "SPCR", acpi_write_spcr, 0);
Patrick Rudolphbf5d3762024-10-23 15:19:54 +0200557
558__weak int acpi_fill_iort(struct acpi_ctx *ctx)
559{
560 return 0;
561}
562
563int acpi_iort_add_its_group(struct acpi_ctx *ctx,
564 const u32 its_count,
565 const u32 *identifiers)
566{
567 struct acpi_iort_node *node;
568 struct acpi_iort_its_group *group;
569 int offset;
570
571 offset = ctx->current - ctx->tab_start;
572
573 node = ctx->current;
574 memset(node, '\0', sizeof(struct acpi_iort_node));
575
576 node->type = ACPI_IORT_NODE_ITS_GROUP;
577 node->revision = 1;
578
579 node->length = sizeof(struct acpi_iort_node);
580 node->length += sizeof(struct acpi_iort_its_group);
581 node->length += sizeof(u32) * its_count;
582
583 group = (struct acpi_iort_its_group *)node->node_data;
584 group->its_count = its_count;
585 memcpy(&group->identifiers, identifiers, sizeof(u32) * its_count);
586
587 ctx->current += node->length;
588
589 return offset;
590}
591
592int acpi_iort_add_named_component(struct acpi_ctx *ctx,
593 const u32 node_flags,
594 const u64 memory_properties,
595 const u8 memory_address_limit,
596 const char *device_name)
597{
598 struct acpi_iort_node *node;
599 struct acpi_iort_named_component *comp;
600 int offset;
601
602 offset = ctx->current - ctx->tab_start;
603
604 node = ctx->current;
605 memset(node, '\0', sizeof(struct acpi_iort_node));
606
607 node->type = ACPI_IORT_NODE_NAMED_COMPONENT;
608 node->revision = 4;
609 node->length = sizeof(struct acpi_iort_node);
610 node->length += sizeof(struct acpi_iort_named_component);
611 node->length += strlen(device_name) + 1;
612
613 comp = (struct acpi_iort_named_component *)node->node_data;
614
615 comp->node_flags = node_flags;
616 comp->memory_properties = memory_properties;
617 comp->memory_address_limit = memory_address_limit;
618 memcpy(comp->device_name, device_name, strlen(device_name) + 1);
619
620 ctx->current += node->length;
621
622 return offset;
623}
624
625int acpi_iort_add_rc(struct acpi_ctx *ctx,
626 const u64 mem_access_properties,
627 const u32 ats_attributes,
628 const u32 pci_segment_number,
629 const u8 memory_address_size_limit,
630 const int num_mappings,
631 const struct acpi_iort_id_mapping *map)
632{
633 struct acpi_iort_id_mapping *mapping;
634 struct acpi_iort_node *node;
635 struct acpi_iort_rc *rc;
636 int offset;
637
638 offset = ctx->current - ctx->tab_start;
639
640 node = ctx->current;
641 memset(node, '\0', sizeof(struct acpi_iort_node));
642
643 node->type = ACPI_IORT_NODE_PCI_ROOT_COMPLEX;
644 node->revision = 2;
645
646 node->length = sizeof(struct acpi_iort_node);
647 node->length += sizeof(struct acpi_iort_rc);
648 node->length += sizeof(struct acpi_iort_id_mapping) * num_mappings;
649
650 rc = (struct acpi_iort_rc *)node->node_data;
651 rc->mem_access_properties = mem_access_properties;
652 rc->ats_attributes = ats_attributes;
653 rc->pci_segment_number = pci_segment_number;
654 rc->memory_address_size_limit = memory_address_size_limit;
655
656 mapping = (struct acpi_iort_id_mapping *)(rc + 1);
657 for (int i = 0; i < num_mappings; i++) {
658 memcpy(mapping, &map[i], sizeof(struct acpi_iort_id_mapping));
659 mapping++;
660 }
661
662 ctx->current += node->length;
663
664 return offset;
665}
666
667int acpi_iort_add_smmu_v3(struct acpi_ctx *ctx,
668 const u64 base_address,
669 const u32 flags,
670 const u64 vatos_address,
671 const u32 model,
672 const u32 event_gsiv,
673 const u32 pri_gsiv,
674 const u32 gerr_gsiv,
675 const u32 sync_gsiv,
676 const u32 pxm,
677 const u32 id_mapping_index,
678 const int num_mappings,
679 const struct acpi_iort_id_mapping *map)
680{
681 struct acpi_iort_node *node;
682 struct acpi_iort_smmu_v3 *smmu;
683 struct acpi_iort_id_mapping *mapping;
684 int offset;
685
686 offset = ctx->current - ctx->tab_start;
687
688 node = ctx->current;
689 memset(node, '\0', sizeof(struct acpi_iort_node));
690
691 node->type = ACPI_IORT_NODE_SMMU_V3;
692 node->revision = 5;
693 node->mapping_count = num_mappings;
694 node->mapping_offset = sizeof(struct acpi_iort_node) + sizeof(struct acpi_iort_smmu_v3);
695
696 node->length = sizeof(struct acpi_iort_node);
697 node->length += sizeof(struct acpi_iort_smmu_v3);
698 node->length += sizeof(struct acpi_iort_id_mapping) * num_mappings;
699
700 smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
701
702 smmu->base_address = base_address;
703 smmu->flags = flags;
704 smmu->vatos_address = vatos_address;
705 smmu->model = model;
706 smmu->event_gsiv = event_gsiv;
707 smmu->pri_gsiv = pri_gsiv;
708 smmu->gerr_gsiv = gerr_gsiv;
709 smmu->sync_gsiv = sync_gsiv;
710 smmu->pxm = pxm;
711 smmu->id_mapping_index = id_mapping_index;
712
713 mapping = (struct acpi_iort_id_mapping *)(smmu + 1);
714 for (int i = 0; i < num_mappings; i++) {
715 memcpy(mapping, &map[i], sizeof(struct acpi_iort_id_mapping));
716 mapping++;
717 }
718
719 ctx->current += node->length;
720
721 return offset;
722}
723
724static int acpi_write_iort(struct acpi_ctx *ctx, const struct acpi_writer *entry)
725{
726 struct acpi_table_iort *iort;
727 struct acpi_iort_node *node;
728 u32 offset;
729 int ret;
730
731 iort = ctx->current;
732 ctx->tab_start = ctx->current;
733 memset(iort, '\0', sizeof(struct acpi_table_iort));
734
735 acpi_fill_header(&iort->header, "IORT");
736 iort->header.revision = 1;
737 iort->header.creator_revision = 1;
738 iort->header.length = sizeof(struct acpi_table_iort);
739 iort->node_offset = sizeof(struct acpi_table_iort);
740
741 acpi_inc(ctx, sizeof(struct acpi_table_iort));
742
743 offset = sizeof(struct acpi_table_iort);
744 ret = acpi_fill_iort(ctx);
745 if (ret) {
746 ctx->current = iort;
747 return log_msg_ret("fill", ret);
748 }
749
750 /* Count nodes filled in */
751 for (node = (void *)iort + iort->node_offset;
752 node->length > 0 && (void *)node < ctx->current;
753 node = (void *)node + node->length)
754 iort->node_count++;
755
756 /* (Re)calculate length and checksum */
757 iort->header.length = ctx->current - (void *)iort;
758 iort->header.checksum = table_compute_checksum((void *)iort, iort->header.length);
759 log_debug("IORT at %p, length %x\n", iort, iort->header.length);
760
761 /* Drop the table if it is empty */
762 if (iort->header.length == sizeof(struct acpi_table_iort))
763 return log_msg_ret("fill", -ENOENT);
764 acpi_add_table(ctx, iort);
765
766 return 0;
767}
768
769ACPI_WRITER(5iort, "IORT", acpi_write_iort, 0);
Patrick Rudolphf570ab62024-10-23 15:19:57 +0200770
771/*
772 * Allocate memory for ACPI tables and write ACPI tables to the
773 * allocated buffer.
774 *
775 * Return: status code
776 */
777static int alloc_write_acpi_tables(void)
778{
779 u64 table_end;
780 void *addr;
781
782 if (IS_ENABLED(CONFIG_X86) ||
783 IS_ENABLED(CONFIG_QFW_ACPI) ||
784 IS_ENABLED(CONFIG_SANDBOX)) {
785 log_debug("Skipping writing ACPI tables as already done\n");
786 return 0;
787 }
788
789 if (!IS_ENABLED(CONFIG_BLOBLIST_TABLES)) {
790 log_debug("Skipping writing ACPI tables as BLOBLIST_TABLES is not selected\n");
791 return 0;
792 }
793
794 /* Align the table to a 4KB boundary to keep EFI happy */
795 addr = bloblist_add(BLOBLISTT_ACPI_TABLES, TABLE_SIZE,
796 ilog2(SZ_4K));
797
798 if (!addr)
799 return log_msg_ret("mem", -ENOMEM);
800
801 gd->arch.table_start_high = virt_to_phys(addr);
802 gd->arch.table_end_high = gd->arch.table_start_high + TABLE_SIZE;
803
804 table_end = write_acpi_tables(gd->arch.table_start_high);
805 if (!table_end) {
806 log_err("Can't create ACPI configuration table\n");
807 return -EINTR;
808 }
809
810 log_debug("- wrote 'acpi' to %lx, end %llx\n", gd->arch.table_start_high, table_end);
811 if (table_end > gd->arch.table_end_high) {
812 log_err("Out of space for configuration tables: need %llx, have %x\n",
813 table_end - gd->arch.table_start_high, TABLE_SIZE);
814 return log_msg_ret("acpi", -ENOSPC);
815 }
816
817 log_debug("- done writing tables\n");
818
819 return 0;
820}
821
822EVENT_SPY_SIMPLE(EVT_LAST_STAGE_INIT, alloc_write_acpi_tables);