uboot/arch/x86/lib/acpi_table.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Based on acpi.c from coreboot
   4 *
   5 * Copyright (C) 2015, Saket Sinha <saket.sinha89@gmail.com>
   6 * Copyright (C) 2016, Bin Meng <bmeng.cn@gmail.com>
   7 */
   8
   9#define LOG_CATEGORY LOGC_ACPI
  10
  11#include <common.h>
  12#include <bloblist.h>
  13#include <cpu.h>
  14#include <dm.h>
  15#include <log.h>
  16#include <dm/uclass-internal.h>
  17#include <mapmem.h>
  18#include <serial.h>
  19#include <acpi/acpigen.h>
  20#include <acpi/acpi_device.h>
  21#include <acpi/acpi_table.h>
  22#include <asm/acpi/global_nvs.h>
  23#include <asm/ioapic.h>
  24#include <asm/global_data.h>
  25#include <asm/lapic.h>
  26#include <asm/mpspec.h>
  27#include <asm/tables.h>
  28#include <asm/arch/global_nvs.h>
  29#include <dm/acpi.h>
  30#include <linux/err.h>
  31
  32static int acpi_create_madt_lapic(struct acpi_madt_lapic *lapic,
  33                                  u8 cpu, u8 apic)
  34{
  35        lapic->type = ACPI_APIC_LAPIC;
  36        lapic->length = sizeof(struct acpi_madt_lapic);
  37        lapic->flags = LOCAL_APIC_FLAG_ENABLED;
  38        lapic->processor_id = cpu;
  39        lapic->apic_id = apic;
  40
  41        return lapic->length;
  42}
  43
  44int acpi_create_madt_lapics(u32 current)
  45{
  46        struct udevice *dev;
  47        int total_length = 0;
  48        int cpu_num = 0;
  49
  50        for (uclass_find_first_device(UCLASS_CPU, &dev);
  51             dev;
  52             uclass_find_next_device(&dev)) {
  53                struct cpu_plat *plat = dev_get_parent_plat(dev);
  54                int length;
  55
  56                length = acpi_create_madt_lapic(
  57                        (struct acpi_madt_lapic *)current, cpu_num++,
  58                        plat->cpu_id);
  59                current += length;
  60                total_length += length;
  61        }
  62
  63        return total_length;
  64}
  65
  66int acpi_create_madt_ioapic(struct acpi_madt_ioapic *ioapic, u8 id,
  67                            u32 addr, u32 gsi_base)
  68{
  69        ioapic->type = ACPI_APIC_IOAPIC;
  70        ioapic->length = sizeof(struct acpi_madt_ioapic);
  71        ioapic->reserved = 0x00;
  72        ioapic->gsi_base = gsi_base;
  73        ioapic->ioapic_id = id;
  74        ioapic->ioapic_addr = addr;
  75
  76        return ioapic->length;
  77}
  78
  79int acpi_create_madt_irqoverride(struct acpi_madt_irqoverride *irqoverride,
  80                                 u8 bus, u8 source, u32 gsirq, u16 flags)
  81{
  82        irqoverride->type = ACPI_APIC_IRQ_SRC_OVERRIDE;
  83        irqoverride->length = sizeof(struct acpi_madt_irqoverride);
  84        irqoverride->bus = bus;
  85        irqoverride->source = source;
  86        irqoverride->gsirq = gsirq;
  87        irqoverride->flags = flags;
  88
  89        return irqoverride->length;
  90}
  91
  92int acpi_create_madt_lapic_nmi(struct acpi_madt_lapic_nmi *lapic_nmi,
  93                               u8 cpu, u16 flags, u8 lint)
  94{
  95        lapic_nmi->type = ACPI_APIC_LAPIC_NMI;
  96        lapic_nmi->length = sizeof(struct acpi_madt_lapic_nmi);
  97        lapic_nmi->flags = flags;
  98        lapic_nmi->processor_id = cpu;
  99        lapic_nmi->lint = lint;
 100
 101        return lapic_nmi->length;
 102}
 103
 104static int acpi_create_madt_irq_overrides(u32 current)
 105{
 106        struct acpi_madt_irqoverride *irqovr;
 107        u16 sci_flags = MP_IRQ_TRIGGER_LEVEL | MP_IRQ_POLARITY_HIGH;
 108        int length = 0;
 109
 110        irqovr = (void *)current;
 111        length += acpi_create_madt_irqoverride(irqovr, 0, 0, 2, 0);
 112
 113        irqovr = (void *)(current + length);
 114        length += acpi_create_madt_irqoverride(irqovr, 0, 9, 9, sci_flags);
 115
 116        return length;
 117}
 118
 119__weak u32 acpi_fill_madt(u32 current)
 120{
 121        current += acpi_create_madt_lapics(current);
 122
 123        current += acpi_create_madt_ioapic((struct acpi_madt_ioapic *)current,
 124                        io_apic_read(IO_APIC_ID) >> 24, IO_APIC_ADDR, 0);
 125
 126        current += acpi_create_madt_irq_overrides(current);
 127
 128        return current;
 129}
 130
 131int acpi_write_madt(struct acpi_ctx *ctx, const struct acpi_writer *entry)
 132{
 133        struct acpi_table_header *header;
 134        struct acpi_madt *madt;
 135        u32 current;
 136
 137        madt = ctx->current;
 138
 139        memset(madt, '\0', sizeof(struct acpi_madt));
 140        header = &madt->header;
 141
 142        /* Fill out header fields */
 143        acpi_fill_header(header, "APIC");
 144        header->length = sizeof(struct acpi_madt);
 145        header->revision = ACPI_MADT_REV_ACPI_3_0;
 146
 147        madt->lapic_addr = LAPIC_DEFAULT_BASE;
 148        madt->flags = ACPI_MADT_PCAT_COMPAT;
 149
 150        current = (u32)madt + sizeof(struct acpi_madt);
 151        current = acpi_fill_madt(current);
 152
 153        /* (Re)calculate length and checksum */
 154        header->length = current - (u32)madt;
 155
 156        header->checksum = table_compute_checksum((void *)madt, header->length);
 157        acpi_add_table(ctx, madt);
 158        acpi_inc(ctx, madt->header.length);
 159
 160        return 0;
 161}
 162ACPI_WRITER(5x86, NULL, acpi_write_madt, 0);
 163
 164/**
 165 * acpi_create_tcpa() - Create a TCPA table
 166 *
 167 * Trusted Computing Platform Alliance Capabilities Table
 168 * TCPA PC Specific Implementation SpecificationTCPA is defined in the PCI
 169 * Firmware Specification 3.0
 170 */
 171int acpi_write_tcpa(struct acpi_ctx *ctx, const struct acpi_writer *entry)
 172{
 173        struct acpi_table_header *header;
 174        struct acpi_tcpa *tcpa;
 175        u32 current;
 176        int size = 0x10000;     /* Use this as the default size */
 177        void *log;
 178        int ret;
 179
 180        if (!IS_ENABLED(CONFIG_TPM_V1))
 181                return -ENOENT;
 182        if (!CONFIG_IS_ENABLED(BLOBLIST))
 183                return -ENXIO;
 184
 185        tcpa = ctx->current;
 186        header = &tcpa->header;
 187        memset(tcpa, '\0', sizeof(struct acpi_tcpa));
 188
 189        /* Fill out header fields */
 190        acpi_fill_header(header, "TCPA");
 191        header->length = sizeof(struct acpi_tcpa);
 192        header->revision = 1;
 193
 194        ret = bloblist_ensure_size_ret(BLOBLISTT_TCPA_LOG, &size, &log);
 195        if (ret)
 196                return log_msg_ret("blob", ret);
 197
 198        tcpa->platform_class = 0;
 199        tcpa->laml = size;
 200        tcpa->lasa = map_to_sysmem(log);
 201
 202        /* (Re)calculate length and checksum */
 203        current = (u32)tcpa + sizeof(struct acpi_tcpa);
 204        header->length = current - (u32)tcpa;
 205        header->checksum = table_compute_checksum(tcpa, header->length);
 206
 207        acpi_inc(ctx, tcpa->header.length);
 208        acpi_add_table(ctx, tcpa);
 209
 210        return 0;
 211}
 212ACPI_WRITER(5tcpa, "TCPA", acpi_write_tcpa, 0);
 213
 214static int get_tpm2_log(void **ptrp, int *sizep)
 215{
 216        const int tpm2_default_log_len = 0x10000;
 217        int size;
 218        int ret;
 219
 220        *sizep = 0;
 221        size = tpm2_default_log_len;
 222        ret = bloblist_ensure_size_ret(BLOBLISTT_TPM2_TCG_LOG, &size, ptrp);
 223        if (ret)
 224                return log_msg_ret("blob", ret);
 225        *sizep = size;
 226
 227        return 0;
 228}
 229
 230static int acpi_write_tpm2(struct acpi_ctx *ctx,
 231                           const struct acpi_writer *entry)
 232{
 233        struct acpi_table_header *header;
 234        struct acpi_tpm2 *tpm2;
 235        int tpm2_log_len;
 236        void *lasa;
 237        int ret;
 238
 239        if (!IS_ENABLED(CONFIG_TPM_V2))
 240                return log_msg_ret("none", -ENOENT);
 241
 242        tpm2 = ctx->current;
 243        header = &tpm2->header;
 244        memset(tpm2, '\0', sizeof(struct acpi_tpm2));
 245
 246        /*
 247         * Some payloads like SeaBIOS depend on log area to use TPM2.
 248         * Get the memory size and address of TPM2 log area or initialize it.
 249         */
 250        ret = get_tpm2_log(&lasa, &tpm2_log_len);
 251        if (ret)
 252                return log_msg_ret("log", ret);
 253
 254        /* Fill out header fields. */
 255        acpi_fill_header(header, "TPM2");
 256        memcpy(header->aslc_id, ASLC_ID, 4);
 257
 258        header->length = sizeof(struct acpi_tpm2);
 259        header->revision = acpi_get_table_revision(ACPITAB_TPM2);
 260
 261        /* Hard to detect for U-Boot. Just set it to 0 */
 262        tpm2->platform_class = 0;
 263
 264        /* Must be set to 0 for FIFO-interface support */
 265        tpm2->control_area = 0;
 266        tpm2->start_method = 6;
 267        memset(tpm2->msp, 0, sizeof(tpm2->msp));
 268
 269        /* Fill the log area size and start address fields. */
 270        tpm2->laml = tpm2_log_len;
 271        tpm2->lasa = map_to_sysmem(lasa);
 272
 273        /* Calculate checksum. */
 274        header->checksum = table_compute_checksum(tpm2, header->length);
 275
 276        acpi_inc(ctx, tpm2->header.length);
 277        acpi_add_table(ctx, tpm2);
 278
 279        return 0;
 280}
 281ACPI_WRITER(5tpm2, "TPM2", acpi_write_tpm2, 0);
 282
 283int acpi_write_spcr(struct acpi_ctx *ctx, const struct acpi_writer *entry)
 284{
 285        struct serial_device_info serial_info = {0};
 286        ulong serial_address, serial_offset;
 287        struct acpi_table_header *header;
 288        struct acpi_spcr *spcr;
 289        struct udevice *dev;
 290        uint serial_config;
 291        uint serial_width;
 292        int access_size;
 293        int space_id;
 294        int ret = -ENODEV;
 295
 296        spcr = ctx->current;
 297        header = &spcr->header;
 298
 299        memset(spcr, '\0', sizeof(struct acpi_spcr));
 300
 301        /* Fill out header fields */
 302        acpi_fill_header(header, "SPCR");
 303        header->length = sizeof(struct acpi_spcr);
 304        header->revision = 2;
 305
 306        /* Read the device once, here. It is reused below */
 307        dev = gd->cur_serial_dev;
 308        if (dev)
 309                ret = serial_getinfo(dev, &serial_info);
 310        if (ret)
 311                serial_info.type = SERIAL_CHIP_UNKNOWN;
 312
 313        /* Encode chip type */
 314        switch (serial_info.type) {
 315        case SERIAL_CHIP_16550_COMPATIBLE:
 316                spcr->interface_type = ACPI_DBG2_16550_COMPATIBLE;
 317                break;
 318        case SERIAL_CHIP_UNKNOWN:
 319        default:
 320                spcr->interface_type = ACPI_DBG2_UNKNOWN;
 321                break;
 322        }
 323
 324        /* Encode address space */
 325        switch (serial_info.addr_space) {
 326        case SERIAL_ADDRESS_SPACE_MEMORY:
 327                space_id = ACPI_ADDRESS_SPACE_MEMORY;
 328                break;
 329        case SERIAL_ADDRESS_SPACE_IO:
 330        default:
 331                space_id = ACPI_ADDRESS_SPACE_IO;
 332                break;
 333        }
 334
 335        serial_width = serial_info.reg_width * 8;
 336        serial_offset = serial_info.reg_offset << serial_info.reg_shift;
 337        serial_address = serial_info.addr + serial_offset;
 338
 339        /* Encode register access size */
 340        switch (serial_info.reg_shift) {
 341        case 0:
 342                access_size = ACPI_ACCESS_SIZE_BYTE_ACCESS;
 343                break;
 344        case 1:
 345                access_size = ACPI_ACCESS_SIZE_WORD_ACCESS;
 346                break;
 347        case 2:
 348                access_size = ACPI_ACCESS_SIZE_DWORD_ACCESS;
 349                break;
 350        case 3:
 351                access_size = ACPI_ACCESS_SIZE_QWORD_ACCESS;
 352                break;
 353        default:
 354                access_size = ACPI_ACCESS_SIZE_UNDEFINED;
 355                break;
 356        }
 357
 358        debug("UART type %u @ %lx\n", spcr->interface_type, serial_address);
 359
 360        /* Fill GAS */
 361        spcr->serial_port.space_id = space_id;
 362        spcr->serial_port.bit_width = serial_width;
 363        spcr->serial_port.bit_offset = 0;
 364        spcr->serial_port.access_size = access_size;
 365        spcr->serial_port.addrl = lower_32_bits(serial_address);
 366        spcr->serial_port.addrh = upper_32_bits(serial_address);
 367
 368        /* Encode baud rate */
 369        switch (serial_info.baudrate) {
 370        case 9600:
 371                spcr->baud_rate = 3;
 372                break;
 373        case 19200:
 374                spcr->baud_rate = 4;
 375                break;
 376        case 57600:
 377                spcr->baud_rate = 6;
 378                break;
 379        case 115200:
 380                spcr->baud_rate = 7;
 381                break;
 382        default:
 383                spcr->baud_rate = 0;
 384                break;
 385        }
 386
 387        serial_config = SERIAL_DEFAULT_CONFIG;
 388        if (dev)
 389                ret = serial_getconfig(dev, &serial_config);
 390
 391        spcr->parity = SERIAL_GET_PARITY(serial_config);
 392        spcr->stop_bits = SERIAL_GET_STOP(serial_config);
 393
 394        /* No PCI devices for now */
 395        spcr->pci_device_id = 0xffff;
 396        spcr->pci_vendor_id = 0xffff;
 397
 398        /*
 399         * SPCR has no clue if the UART base clock speed is different
 400         * to the default one. However, the SPCR 1.04 defines baud rate
 401         * 0 as a preconfigured state of UART and OS is supposed not
 402         * to touch the configuration of the serial device.
 403         */
 404        if (serial_info.clock != SERIAL_DEFAULT_CLOCK)
 405                spcr->baud_rate = 0;
 406
 407        /* Fix checksum */
 408        header->checksum = table_compute_checksum((void *)spcr, header->length);
 409
 410        acpi_add_table(ctx, spcr);
 411        acpi_inc(ctx, spcr->header.length);
 412
 413        return 0;
 414}
 415ACPI_WRITER(5spcr, "SPCR", acpi_write_spcr, 0);
 416
 417int acpi_write_gnvs(struct acpi_ctx *ctx, const struct acpi_writer *entry)
 418{
 419        ulong addr;
 420
 421        if (!IS_ENABLED(CONFIG_ACPI_GNVS_EXTERNAL)) {
 422                int i;
 423
 424                /* We need the DSDT to be done */
 425                if (!ctx->dsdt)
 426                        return log_msg_ret("dsdt", -EAGAIN);
 427
 428                /* Pack GNVS into the ACPI table area */
 429                for (i = 0; i < ctx->dsdt->length; i++) {
 430                        u32 *gnvs = (u32 *)((u32)ctx->dsdt + i);
 431
 432                        if (*gnvs == ACPI_GNVS_ADDR) {
 433                                *gnvs = map_to_sysmem(ctx->current);
 434                                log_debug("Fix up global NVS in DSDT to %#08x\n",
 435                                          *gnvs);
 436                                break;
 437                        }
 438                }
 439
 440                /*
 441                 * Recalculate the length and update the DSDT checksum since we
 442                 * patched the GNVS address. Set the checksum to zero since it
 443                 * is part of the region being checksummed.
 444                 */
 445                ctx->dsdt->checksum = 0;
 446                ctx->dsdt->checksum = table_compute_checksum((void *)ctx->dsdt,
 447                                                             ctx->dsdt->length);
 448        }
 449
 450        /* Fill in platform-specific global NVS variables */
 451        addr = acpi_create_gnvs(ctx->current);
 452        if (IS_ERR_VALUE(addr))
 453                return log_msg_ret("gnvs", (int)addr);
 454
 455        acpi_inc_align(ctx, sizeof(struct acpi_global_nvs));
 456
 457        return 0;
 458}
 459ACPI_WRITER(4gnvs, "GNVS", acpi_write_gnvs, 0);
 460
 461static int acpi_write_fadt(struct acpi_ctx *ctx,
 462                           const struct acpi_writer *entry)
 463{
 464        struct acpi_fadt *fadt;
 465
 466        fadt = ctx->current;
 467        acpi_create_fadt(fadt, ctx->facs, ctx->dsdt);
 468        acpi_add_table(ctx, fadt);
 469
 470        acpi_inc(ctx, sizeof(struct acpi_fadt));
 471
 472        return 0;
 473}
 474ACPI_WRITER(5fact, "FADT", acpi_write_fadt, 0);
 475
 476/**
 477 * acpi_write_hpet() - Write out a HPET table
 478 *
 479 * Write out the table for High-Precision Event Timers
 480 *
 481 * @hpet: Place to put HPET table
 482 */
 483static int acpi_create_hpet(struct acpi_hpet *hpet)
 484{
 485        struct acpi_table_header *header = &hpet->header;
 486        struct acpi_gen_regaddr *addr = &hpet->addr;
 487
 488        /*
 489         * See IA-PC HPET (High Precision Event Timers) Specification v1.0a
 490         * https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/software-developers-hpet-spec-1-0a.pdf
 491         */
 492        memset((void *)hpet, '\0', sizeof(struct acpi_hpet));
 493
 494        /* Fill out header fields. */
 495        acpi_fill_header(header, "HPET");
 496
 497        header->aslc_revision = ASL_REVISION;
 498        header->length = sizeof(struct acpi_hpet);
 499        header->revision = acpi_get_table_revision(ACPITAB_HPET);
 500
 501        /* Fill out HPET address */
 502        addr->space_id = 0;  /* Memory */
 503        addr->bit_width = 64;
 504        addr->bit_offset = 0;
 505        addr->addrl = CONFIG_HPET_ADDRESS & 0xffffffff;
 506        addr->addrh = ((unsigned long long)CONFIG_HPET_ADDRESS) >> 32;
 507
 508        hpet->id = *(u32 *)CONFIG_HPET_ADDRESS;
 509        hpet->number = 0;
 510        hpet->min_tick = 0; /* HPET_MIN_TICKS */
 511
 512        header->checksum = table_compute_checksum(hpet,
 513                                                  sizeof(struct acpi_hpet));
 514
 515        return 0;
 516}
 517
 518int acpi_write_hpet(struct acpi_ctx *ctx)
 519{
 520        struct acpi_hpet *hpet;
 521        int ret;
 522
 523        log_debug("ACPI:    * HPET\n");
 524
 525        hpet = ctx->current;
 526        acpi_inc_align(ctx, sizeof(struct acpi_hpet));
 527        acpi_create_hpet(hpet);
 528        ret = acpi_add_table(ctx, hpet);
 529        if (ret)
 530                return log_msg_ret("add", ret);
 531
 532        return 0;
 533}
 534
 535int acpi_write_dbg2_pci_uart(struct acpi_ctx *ctx, struct udevice *dev,
 536                             uint access_size)
 537{
 538        struct acpi_dbg2_header *dbg2 = ctx->current;
 539        char path[ACPI_PATH_MAX];
 540        struct acpi_gen_regaddr address;
 541        phys_addr_t addr;
 542        int ret;
 543
 544        if (!device_active(dev)) {
 545                log_info("Device not enabled\n");
 546                return -EACCES;
 547        }
 548        /*
 549         * PCI devices don't remember their resource allocation information in
 550         * U-Boot at present. We assume that MMIO is used for the UART and that
 551         * the address space is 32 bytes: ns16550 uses 8 registers of up to
 552         * 32-bits each. This is only for debugging so it is not a big deal.
 553         */
 554        addr = dm_pci_read_bar32(dev, 0);
 555        log_debug("UART addr %lx\n", (ulong)addr);
 556
 557        memset(&address, '\0', sizeof(address));
 558        address.space_id = ACPI_ADDRESS_SPACE_MEMORY;
 559        address.addrl = (uint32_t)addr;
 560        address.addrh = (uint32_t)((addr >> 32) & 0xffffffff);
 561        address.access_size = access_size;
 562
 563        ret = acpi_device_path(dev, path, sizeof(path));
 564        if (ret)
 565                return log_msg_ret("path", ret);
 566        acpi_create_dbg2(dbg2, ACPI_DBG2_SERIAL_PORT,
 567                         ACPI_DBG2_16550_COMPATIBLE, &address, 0x1000, path);
 568
 569        acpi_inc_align(ctx, dbg2->header.length);
 570        acpi_add_table(ctx, dbg2);
 571
 572        return 0;
 573}
 574
 575void acpi_fadt_common(struct acpi_fadt *fadt, struct acpi_facs *facs,
 576                      void *dsdt)
 577{
 578        struct acpi_table_header *header = &fadt->header;
 579
 580        memset((void *)fadt, '\0', sizeof(struct acpi_fadt));
 581
 582        acpi_fill_header(header, "FACP");
 583        header->length = sizeof(struct acpi_fadt);
 584        header->revision = 4;
 585        memcpy(header->oem_id, OEM_ID, 6);
 586        memcpy(header->oem_table_id, OEM_TABLE_ID, 8);
 587        memcpy(header->aslc_id, ASLC_ID, 4);
 588        header->aslc_revision = 1;
 589
 590        fadt->firmware_ctrl = (unsigned long)facs;
 591        fadt->dsdt = (unsigned long)dsdt;
 592
 593        fadt->x_firmware_ctl_l = (unsigned long)facs;
 594        fadt->x_firmware_ctl_h = 0;
 595        fadt->x_dsdt_l = (unsigned long)dsdt;
 596        fadt->x_dsdt_h = 0;
 597
 598        fadt->preferred_pm_profile = ACPI_PM_MOBILE;
 599
 600        /* Use ACPI 3.0 revision */
 601        fadt->header.revision = 4;
 602}
 603
 604void acpi_create_dmar_drhd(struct acpi_ctx *ctx, uint flags, uint segment,
 605                           u64 bar)
 606{
 607        struct dmar_entry *drhd = ctx->current;
 608
 609        memset(drhd, '\0', sizeof(*drhd));
 610        drhd->type = DMAR_DRHD;
 611        drhd->length = sizeof(*drhd); /* will be fixed up later */
 612        drhd->flags = flags;
 613        drhd->segment = segment;
 614        drhd->bar = bar;
 615        acpi_inc(ctx, drhd->length);
 616}
 617
 618void acpi_create_dmar_rmrr(struct acpi_ctx *ctx, uint segment, u64 bar,
 619                           u64 limit)
 620{
 621        struct dmar_rmrr_entry *rmrr = ctx->current;
 622
 623        memset(rmrr, '\0', sizeof(*rmrr));
 624        rmrr->type = DMAR_RMRR;
 625        rmrr->length = sizeof(*rmrr); /* will be fixed up later */
 626        rmrr->segment = segment;
 627        rmrr->bar = bar;
 628        rmrr->limit = limit;
 629        acpi_inc(ctx, rmrr->length);
 630}
 631
 632void acpi_dmar_drhd_fixup(struct acpi_ctx *ctx, void *base)
 633{
 634        struct dmar_entry *drhd = base;
 635
 636        drhd->length = ctx->current - base;
 637}
 638
 639void acpi_dmar_rmrr_fixup(struct acpi_ctx *ctx, void *base)
 640{
 641        struct dmar_rmrr_entry *rmrr = base;
 642
 643        rmrr->length = ctx->current - base;
 644}
 645
 646static int acpi_create_dmar_ds(struct acpi_ctx *ctx, enum dev_scope_type type,
 647                               uint enumeration_id, pci_dev_t bdf)
 648{
 649        /* we don't support longer paths yet */
 650        const size_t dev_scope_length = sizeof(struct dev_scope) + 2;
 651        struct dev_scope *ds = ctx->current;
 652
 653        memset(ds, '\0', dev_scope_length);
 654        ds->type = type;
 655        ds->length = dev_scope_length;
 656        ds->enumeration = enumeration_id;
 657        ds->start_bus = PCI_BUS(bdf);
 658        ds->path[0].dev = PCI_DEV(bdf);
 659        ds->path[0].fn = PCI_FUNC(bdf);
 660
 661        return ds->length;
 662}
 663
 664int acpi_create_dmar_ds_pci_br(struct acpi_ctx *ctx, pci_dev_t bdf)
 665{
 666        return acpi_create_dmar_ds(ctx, SCOPE_PCI_SUB, 0, bdf);
 667}
 668
 669int acpi_create_dmar_ds_pci(struct acpi_ctx *ctx, pci_dev_t bdf)
 670{
 671        return acpi_create_dmar_ds(ctx, SCOPE_PCI_ENDPOINT, 0, bdf);
 672}
 673
 674int acpi_create_dmar_ds_ioapic(struct acpi_ctx *ctx, uint enumeration_id,
 675                               pci_dev_t bdf)
 676{
 677        return acpi_create_dmar_ds(ctx, SCOPE_IOAPIC, enumeration_id, bdf);
 678}
 679
 680int acpi_create_dmar_ds_msi_hpet(struct acpi_ctx *ctx, uint enumeration_id,
 681                                 pci_dev_t bdf)
 682{
 683        return acpi_create_dmar_ds(ctx, SCOPE_MSI_HPET, enumeration_id, bdf);
 684}
 685