blob: e6ebffcf1b0a246b6bbd890c348c2b391059d296 [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 Rudolph4a3fc0f2024-10-23 15:19:46 +0200300 header->checksum = table_compute_checksum((void *)madt, header->length);
301 acpi_add_table(ctx, madt);
302 ctx->current = (void *)madt + madt->header.length;
303
304 return 0;
305}
306
307ACPI_WRITER(5madt, "MADT", acpi_write_madt, 0);
308
Simon Glassf37979e2020-09-22 12:45:10 -0600309void acpi_create_dbg2(struct acpi_dbg2_header *dbg2,
310 int port_type, int port_subtype,
311 struct acpi_gen_regaddr *address, u32 address_size,
312 const char *device_path)
313{
314 uintptr_t current;
315 struct acpi_dbg2_device *device;
316 u32 *dbg2_addr_size;
317 struct acpi_table_header *header;
318 size_t path_len;
319 const char *path;
320 char *namespace;
321
322 /* Fill out header fields. */
323 current = (uintptr_t)dbg2;
324 memset(dbg2, '\0', sizeof(struct acpi_dbg2_header));
325 header = &dbg2->header;
326
327 header->revision = acpi_get_table_revision(ACPITAB_DBG2);
328 acpi_fill_header(header, "DBG2");
Simon Glassf37979e2020-09-22 12:45:10 -0600329
330 /* One debug device defined */
331 dbg2->devices_offset = sizeof(struct acpi_dbg2_header);
332 dbg2->devices_count = 1;
333 current += sizeof(struct acpi_dbg2_header);
334
335 /* Device comes after the header */
336 device = (struct acpi_dbg2_device *)current;
337 memset(device, 0, sizeof(struct acpi_dbg2_device));
338 current += sizeof(struct acpi_dbg2_device);
339
340 device->revision = 0;
341 device->address_count = 1;
342 device->port_type = port_type;
343 device->port_subtype = port_subtype;
344
345 /* Base Address comes after device structure */
346 memcpy((void *)current, address, sizeof(struct acpi_gen_regaddr));
347 device->base_address_offset = current - (uintptr_t)device;
348 current += sizeof(struct acpi_gen_regaddr);
349
350 /* Address Size comes after address structure */
351 dbg2_addr_size = (uint32_t *)current;
352 device->address_size_offset = current - (uintptr_t)device;
353 *dbg2_addr_size = address_size;
354 current += sizeof(uint32_t);
355
356 /* Namespace string comes last, use '.' if not provided */
357 path = device_path ? : ".";
358 /* Namespace string length includes NULL terminator */
359 path_len = strlen(path) + 1;
360 namespace = (char *)current;
361 device->namespace_string_length = path_len;
362 device->namespace_string_offset = current - (uintptr_t)device;
363 strncpy(namespace, path, path_len);
364 current += path_len;
365
366 /* Update structure lengths and checksum */
367 device->length = current - (uintptr_t)device;
368 header->length = current - (uintptr_t)dbg2;
369 header->checksum = table_compute_checksum(dbg2, header->length);
370}
Maximilian Brune1c03efc2024-10-23 15:19:44 +0200371
372int acpi_write_dbg2_pci_uart(struct acpi_ctx *ctx, struct udevice *dev,
373 uint access_size)
374{
375 struct acpi_dbg2_header *dbg2 = ctx->current;
376 char path[ACPI_PATH_MAX];
377 struct acpi_gen_regaddr address;
378 u64 addr;
379 int ret;
380
381 if (!device_active(dev)) {
382 log_info("Device not enabled\n");
383 return -EACCES;
384 }
385 /*
386 * PCI devices don't remember their resource allocation information in
387 * U-Boot at present. We assume that MMIO is used for the UART and that
388 * the address space is 32 bytes: ns16550 uses 8 registers of up to
389 * 32-bits each. This is only for debugging so it is not a big deal.
390 */
391 addr = dm_pci_read_bar32(dev, 0);
392 log_debug("UART addr %lx\n", (ulong)addr);
393
394 ret = acpi_device_path(dev, path, sizeof(path));
395 if (ret)
396 return log_msg_ret("path", ret);
397
398 memset(&address, '\0', sizeof(address));
399 address.space_id = ACPI_ADDRESS_SPACE_MEMORY;
400 address.addrl = (uint32_t)addr;
401 address.addrh = (uint32_t)((addr >> 32) & 0xffffffff);
402 address.access_size = access_size;
403
404 ret = acpi_device_path(dev, path, sizeof(path));
405 if (ret)
406 return log_msg_ret("path", ret);
407 acpi_create_dbg2(dbg2, ACPI_DBG2_SERIAL_PORT,
408 ACPI_DBG2_16550_COMPATIBLE, &address, 0x1000, path);
409
410 acpi_inc_align(ctx, dbg2->header.length);
411 acpi_add_table(ctx, dbg2);
412
413 return 0;
414}
415
416static int acpi_write_spcr(struct acpi_ctx *ctx, const struct acpi_writer *entry)
417{
418 struct serial_device_info serial_info = {0};
419 ulong serial_address, serial_offset;
420 struct acpi_table_header *header;
421 struct acpi_spcr *spcr;
422 struct udevice *dev;
423 uint serial_config;
424 uint serial_width;
425 int access_size;
426 int space_id;
427 int ret = -ENODEV;
428
429 spcr = ctx->current;
430 header = &spcr->header;
431
432 memset(spcr, '\0', sizeof(struct acpi_spcr));
433
434 /* Fill out header fields */
435 acpi_fill_header(header, "SPCR");
436 header->length = sizeof(struct acpi_spcr);
437 header->revision = 2;
438
439 /* Read the device once, here. It is reused below */
440 dev = gd->cur_serial_dev;
441 if (dev)
442 ret = serial_getinfo(dev, &serial_info);
443 if (ret)
444 serial_info.type = SERIAL_CHIP_UNKNOWN;
445
446 /* Encode chip type */
447 switch (serial_info.type) {
448 case SERIAL_CHIP_16550_COMPATIBLE:
449 spcr->interface_type = ACPI_DBG2_16550_COMPATIBLE;
450 break;
451 case SERIAL_CHIP_PL01X:
452 spcr->interface_type = ACPI_DBG2_ARM_PL011;
453 break;
454 case SERIAL_CHIP_UNKNOWN:
455 default:
456 spcr->interface_type = ACPI_DBG2_UNKNOWN;
457 break;
458 }
459
460 /* Encode address space */
461 switch (serial_info.addr_space) {
462 case SERIAL_ADDRESS_SPACE_MEMORY:
463 space_id = ACPI_ADDRESS_SPACE_MEMORY;
464 break;
465 case SERIAL_ADDRESS_SPACE_IO:
466 default:
467 space_id = ACPI_ADDRESS_SPACE_IO;
468 break;
469 }
470
471 serial_width = serial_info.reg_width * 8;
472 serial_offset = serial_info.reg_offset << serial_info.reg_shift;
473 serial_address = serial_info.addr + serial_offset;
474
475 /* Encode register access size */
476 switch (serial_info.reg_shift) {
477 case 0:
478 access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
479 break;
480 case 1:
481 access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
482 break;
483 case 2:
484 access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
485 break;
486 case 3:
487 access_size = ACPI_ACCESS_SIZE_QWORD_ACCESS;
488 break;
489 default:
490 access_size = ACPI_ACCESS_SIZE_UNDEFINED;
491 break;
492 }
493
494 debug("UART type %u @ %lx\n", spcr->interface_type, serial_address);
495
496 /* Fill GAS */
497 spcr->serial_port.space_id = space_id;
498 spcr->serial_port.bit_width = serial_width;
499 spcr->serial_port.bit_offset = 0;
500 spcr->serial_port.access_size = access_size;
501 spcr->serial_port.addrl = lower_32_bits(serial_address);
502 spcr->serial_port.addrh = upper_32_bits(serial_address);
503
504 /* Encode baud rate */
505 switch (serial_info.baudrate) {
506 case 9600:
507 spcr->baud_rate = 3;
508 break;
509 case 19200:
510 spcr->baud_rate = 4;
511 break;
512 case 57600:
513 spcr->baud_rate = 6;
514 break;
515 case 115200:
516 spcr->baud_rate = 7;
517 break;
518 default:
519 spcr->baud_rate = 0;
520 break;
521 }
522
523 serial_config = SERIAL_DEFAULT_CONFIG;
524 if (dev)
525 ret = serial_getconfig(dev, &serial_config);
526
527 spcr->parity = SERIAL_GET_PARITY(serial_config);
528 spcr->stop_bits = SERIAL_GET_STOP(serial_config);
529
530 /* No PCI devices for now */
531 spcr->pci_device_id = 0xffff;
532 spcr->pci_vendor_id = 0xffff;
533
534 /*
535 * SPCR has no clue if the UART base clock speed is different
536 * to the default one. However, the SPCR 1.04 defines baud rate
537 * 0 as a preconfigured state of UART and OS is supposed not
538 * to touch the configuration of the serial device.
539 */
540 if (serial_info.clock != SERIAL_DEFAULT_CLOCK)
541 spcr->baud_rate = 0;
542
543 /* Fix checksum */
544 header->checksum = table_compute_checksum((void *)spcr, header->length);
545
546 acpi_add_table(ctx, spcr);
547 acpi_inc(ctx, spcr->header.length);
548
549 return 0;
550}
551
552ACPI_WRITER(5spcr, "SPCR", acpi_write_spcr, 0);
Patrick Rudolphbf5d3762024-10-23 15:19:54 +0200553
554__weak int acpi_fill_iort(struct acpi_ctx *ctx)
555{
556 return 0;
557}
558
559int acpi_iort_add_its_group(struct acpi_ctx *ctx,
560 const u32 its_count,
561 const u32 *identifiers)
562{
563 struct acpi_iort_node *node;
564 struct acpi_iort_its_group *group;
565 int offset;
566
567 offset = ctx->current - ctx->tab_start;
568
569 node = ctx->current;
570 memset(node, '\0', sizeof(struct acpi_iort_node));
571
572 node->type = ACPI_IORT_NODE_ITS_GROUP;
573 node->revision = 1;
574
575 node->length = sizeof(struct acpi_iort_node);
576 node->length += sizeof(struct acpi_iort_its_group);
577 node->length += sizeof(u32) * its_count;
578
579 group = (struct acpi_iort_its_group *)node->node_data;
580 group->its_count = its_count;
581 memcpy(&group->identifiers, identifiers, sizeof(u32) * its_count);
582
583 ctx->current += node->length;
584
585 return offset;
586}
587
588int acpi_iort_add_named_component(struct acpi_ctx *ctx,
589 const u32 node_flags,
590 const u64 memory_properties,
591 const u8 memory_address_limit,
592 const char *device_name)
593{
594 struct acpi_iort_node *node;
595 struct acpi_iort_named_component *comp;
596 int offset;
597
598 offset = ctx->current - ctx->tab_start;
599
600 node = ctx->current;
601 memset(node, '\0', sizeof(struct acpi_iort_node));
602
603 node->type = ACPI_IORT_NODE_NAMED_COMPONENT;
604 node->revision = 4;
605 node->length = sizeof(struct acpi_iort_node);
606 node->length += sizeof(struct acpi_iort_named_component);
607 node->length += strlen(device_name) + 1;
608
609 comp = (struct acpi_iort_named_component *)node->node_data;
610
611 comp->node_flags = node_flags;
612 comp->memory_properties = memory_properties;
613 comp->memory_address_limit = memory_address_limit;
614 memcpy(comp->device_name, device_name, strlen(device_name) + 1);
615
616 ctx->current += node->length;
617
618 return offset;
619}
620
621int acpi_iort_add_rc(struct acpi_ctx *ctx,
622 const u64 mem_access_properties,
623 const u32 ats_attributes,
624 const u32 pci_segment_number,
625 const u8 memory_address_size_limit,
626 const int num_mappings,
627 const struct acpi_iort_id_mapping *map)
628{
629 struct acpi_iort_id_mapping *mapping;
630 struct acpi_iort_node *node;
631 struct acpi_iort_rc *rc;
632 int offset;
633
634 offset = ctx->current - ctx->tab_start;
635
636 node = ctx->current;
637 memset(node, '\0', sizeof(struct acpi_iort_node));
638
639 node->type = ACPI_IORT_NODE_PCI_ROOT_COMPLEX;
640 node->revision = 2;
641
642 node->length = sizeof(struct acpi_iort_node);
643 node->length += sizeof(struct acpi_iort_rc);
644 node->length += sizeof(struct acpi_iort_id_mapping) * num_mappings;
645
646 rc = (struct acpi_iort_rc *)node->node_data;
647 rc->mem_access_properties = mem_access_properties;
648 rc->ats_attributes = ats_attributes;
649 rc->pci_segment_number = pci_segment_number;
650 rc->memory_address_size_limit = memory_address_size_limit;
651
652 mapping = (struct acpi_iort_id_mapping *)(rc + 1);
653 for (int i = 0; i < num_mappings; i++) {
654 memcpy(mapping, &map[i], sizeof(struct acpi_iort_id_mapping));
655 mapping++;
656 }
657
658 ctx->current += node->length;
659
660 return offset;
661}
662
663int acpi_iort_add_smmu_v3(struct acpi_ctx *ctx,
664 const u64 base_address,
665 const u32 flags,
666 const u64 vatos_address,
667 const u32 model,
668 const u32 event_gsiv,
669 const u32 pri_gsiv,
670 const u32 gerr_gsiv,
671 const u32 sync_gsiv,
672 const u32 pxm,
673 const u32 id_mapping_index,
674 const int num_mappings,
675 const struct acpi_iort_id_mapping *map)
676{
677 struct acpi_iort_node *node;
678 struct acpi_iort_smmu_v3 *smmu;
679 struct acpi_iort_id_mapping *mapping;
680 int offset;
681
682 offset = ctx->current - ctx->tab_start;
683
684 node = ctx->current;
685 memset(node, '\0', sizeof(struct acpi_iort_node));
686
687 node->type = ACPI_IORT_NODE_SMMU_V3;
688 node->revision = 5;
689 node->mapping_count = num_mappings;
690 node->mapping_offset = sizeof(struct acpi_iort_node) + sizeof(struct acpi_iort_smmu_v3);
691
692 node->length = sizeof(struct acpi_iort_node);
693 node->length += sizeof(struct acpi_iort_smmu_v3);
694 node->length += sizeof(struct acpi_iort_id_mapping) * num_mappings;
695
696 smmu = (struct acpi_iort_smmu_v3 *)node->node_data;
697
698 smmu->base_address = base_address;
699 smmu->flags = flags;
700 smmu->vatos_address = vatos_address;
701 smmu->model = model;
702 smmu->event_gsiv = event_gsiv;
703 smmu->pri_gsiv = pri_gsiv;
704 smmu->gerr_gsiv = gerr_gsiv;
705 smmu->sync_gsiv = sync_gsiv;
706 smmu->pxm = pxm;
707 smmu->id_mapping_index = id_mapping_index;
708
709 mapping = (struct acpi_iort_id_mapping *)(smmu + 1);
710 for (int i = 0; i < num_mappings; i++) {
711 memcpy(mapping, &map[i], sizeof(struct acpi_iort_id_mapping));
712 mapping++;
713 }
714
715 ctx->current += node->length;
716
717 return offset;
718}
719
720static int acpi_write_iort(struct acpi_ctx *ctx, const struct acpi_writer *entry)
721{
722 struct acpi_table_iort *iort;
723 struct acpi_iort_node *node;
724 u32 offset;
725 int ret;
726
727 iort = ctx->current;
728 ctx->tab_start = ctx->current;
729 memset(iort, '\0', sizeof(struct acpi_table_iort));
730
731 acpi_fill_header(&iort->header, "IORT");
732 iort->header.revision = 1;
733 iort->header.creator_revision = 1;
734 iort->header.length = sizeof(struct acpi_table_iort);
735 iort->node_offset = sizeof(struct acpi_table_iort);
736
737 acpi_inc(ctx, sizeof(struct acpi_table_iort));
738
739 offset = sizeof(struct acpi_table_iort);
740 ret = acpi_fill_iort(ctx);
741 if (ret) {
742 ctx->current = iort;
743 return log_msg_ret("fill", ret);
744 }
745
746 /* Count nodes filled in */
747 for (node = (void *)iort + iort->node_offset;
748 node->length > 0 && (void *)node < ctx->current;
749 node = (void *)node + node->length)
750 iort->node_count++;
751
752 /* (Re)calculate length and checksum */
753 iort->header.length = ctx->current - (void *)iort;
754 iort->header.checksum = table_compute_checksum((void *)iort, iort->header.length);
755 log_debug("IORT at %p, length %x\n", iort, iort->header.length);
756
757 /* Drop the table if it is empty */
758 if (iort->header.length == sizeof(struct acpi_table_iort))
759 return log_msg_ret("fill", -ENOENT);
760 acpi_add_table(ctx, iort);
761
762 return 0;
763}
764
765ACPI_WRITER(5iort, "IORT", acpi_write_iort, 0);
Patrick Rudolphf570ab62024-10-23 15:19:57 +0200766
767/*
768 * Allocate memory for ACPI tables and write ACPI tables to the
769 * allocated buffer.
770 *
771 * Return: status code
772 */
773static int alloc_write_acpi_tables(void)
774{
775 u64 table_end;
776 void *addr;
777
778 if (IS_ENABLED(CONFIG_X86) ||
779 IS_ENABLED(CONFIG_QFW_ACPI) ||
780 IS_ENABLED(CONFIG_SANDBOX)) {
781 log_debug("Skipping writing ACPI tables as already done\n");
782 return 0;
783 }
784
785 if (!IS_ENABLED(CONFIG_BLOBLIST_TABLES)) {
786 log_debug("Skipping writing ACPI tables as BLOBLIST_TABLES is not selected\n");
787 return 0;
788 }
789
790 /* Align the table to a 4KB boundary to keep EFI happy */
791 addr = bloblist_add(BLOBLISTT_ACPI_TABLES, TABLE_SIZE,
792 ilog2(SZ_4K));
793
794 if (!addr)
795 return log_msg_ret("mem", -ENOMEM);
796
797 gd->arch.table_start_high = virt_to_phys(addr);
798 gd->arch.table_end_high = gd->arch.table_start_high + TABLE_SIZE;
799
800 table_end = write_acpi_tables(gd->arch.table_start_high);
801 if (!table_end) {
802 log_err("Can't create ACPI configuration table\n");
803 return -EINTR;
804 }
805
806 log_debug("- wrote 'acpi' to %lx, end %llx\n", gd->arch.table_start_high, table_end);
807 if (table_end > gd->arch.table_end_high) {
808 log_err("Out of space for configuration tables: need %llx, have %x\n",
809 table_end - gd->arch.table_start_high, TABLE_SIZE);
810 return log_msg_ret("acpi", -ENOSPC);
811 }
812
813 log_debug("- done writing tables\n");
814
815 return 0;
816}
817
818EVENT_SPY_SIMPLE(EVT_LAST_STAGE_INIT, alloc_write_acpi_tables);