[U-Boot] [UBOOT PATCH v5 0/3] Add ACPI table support

ACPI(Advanced Configuration and Power Interface), is a Power Management and configuration standard allowing the operating system to control the amount of power each device is given (allowing it to put certain devices on standby or power-off for example). It is also used to control and/or check thermal zones (temperature sensors, fan speeds, etc), battery levels, PCI IRQ routing, CPUs, NUMA domains and many other things.
Changes in v5: - Incoporated Simon's review comments.
Saket Sinha (3): x86: Generate a valid ACPI table x86: Add ACPI table support to QEMU x86: Add DSDT table for supporting ACPI on QEMU
arch/x86/Kconfig | 9 + arch/x86/cpu/qemu/Makefile | 1 + arch/x86/cpu/qemu/acpi.c | 179 ++++++++++++++ arch/x86/cpu/qemu/acpi/cpu-hotplug.asl | 78 ++++++ arch/x86/cpu/qemu/acpi/dbug.asl | 26 ++ arch/x86/cpu/qemu/acpi/hpet.asl | 33 +++ arch/x86/cpu/qemu/acpi/isa.asl | 102 ++++++++ arch/x86/cpu/qemu/acpi/pci-crs.asl | 61 +++++ arch/x86/cpu/qemu/dsdt.asl | 414 +++++++++++++++++++++++++++++++ arch/x86/include/asm/acpi_table.h | 390 +++++++++++++++++++++++++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/acpi_table.c | 433 +++++++++++++++++++++++++++++++++ arch/x86/lib/tables.c | 5 + scripts/Makefile.lib | 11 + 14 files changed, 1743 insertions(+) create mode 100644 arch/x86/cpu/qemu/acpi.c create mode 100644 arch/x86/cpu/qemu/acpi/cpu-hotplug.asl create mode 100644 arch/x86/cpu/qemu/acpi/dbug.asl create mode 100644 arch/x86/cpu/qemu/acpi/hpet.asl create mode 100644 arch/x86/cpu/qemu/acpi/isa.asl create mode 100644 arch/x86/cpu/qemu/acpi/pci-crs.asl create mode 100644 arch/x86/cpu/qemu/dsdt.asl create mode 100644 arch/x86/include/asm/acpi_table.h create mode 100644 arch/x86/lib/acpi_table.c

Implement write_acpi_table() to create a minimal working ACPI table. This includes writing FACS, XSDT, RSDP, FADT, MCFG, MADT, DSDT & SSDT ACPI table entries.
Use a Kconfig option GENERATE_ACPI_TABLE to tell U-Boot whether we need actually write the APCI table just like we did for PIRQ routing, MP table and SFI tables. With ACPI table existence, linux kernel gets control of power management, thermal management, configuration management and monitoring in hardware.
Signed-off-by: Saket Sinha saket.sinha89@gmail.com ---
arch/x86/Kconfig | 9 + arch/x86/include/asm/acpi_table.h | 390 ++++++++++++++++++++++++++++++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/acpi_table.c | 433 ++++++++++++++++++++++++++++++++++++++ arch/x86/lib/tables.c | 5 + scripts/Makefile.lib | 11 + 6 files changed, 849 insertions(+) create mode 100644 arch/x86/include/asm/acpi_table.h create mode 100644 arch/x86/lib/acpi_table.c
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 01ed760..ae881a1 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -344,6 +344,15 @@ config GENERATE_MP_TABLE multiprocessing as well as symmetric I/O interrupt handling with the local APIC and I/O APIC.
+config GENERATE_ACPI_TABLE + bool "Generate an ACPI (Advanced Configuration and Power Interface) table" + default n + help + The Advanced Configuration and Power Interface (ACPI) specification + provides an open standard for device configuration and management + by the operating system. It defines platform-independent interfaces + for configuration and power management monitoring. + endmenu
config MAX_PIRQ_LINKS diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h new file mode 100644 index 0000000..a813a0a --- /dev/null +++ b/arch/x86/include/asm/acpi_table.h @@ -0,0 +1,390 @@ +/* + * Based on acpi.c from coreboot + * + * Copyright (C) 2015, Saket Sinha saket.sinha89@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <malloc.h> +#include <asm/post.h> +#include <linux/string.h> + +#define RSDP_SIG "RSD PTR " /* RSDT pointer signature */ +#define ACPI_TABLE_CREATOR "UBOOT " /* Must be exactly 8 bytes long! */ +#define OEM_ID "UBOOT " /* Must be exactly 6 bytes long! */ +#define ASLC "INTL" /* Must be exactly 4 bytes long! */ + +#define OEM_REVISION 42 +#define ASL_COMPILER_REVISION 42 + +#define APM_CNT 0xb2 +#define APM_CNT_CST_CONTROL 0x85 +#define APM_CNT_PST_CONTROL 0x80 +#define APM_CNT_ACPI_DISABLE 0x1e +#define APM_CNT_ACPI_ENABLE 0xe1 +#define APM_CNT_MBI_UPDATE 0xeb +#define APM_CNT_GNVS_UPDATE 0xea +#define APM_CNT_FINALIZE 0xcb +#define APM_CNT_LEGACY 0xcc +#define APM_ST 0xb3 + +#define MP_IRQ_POLARITY_DEFAULT 0x0 +#define MP_IRQ_POLARITY_HIGH 0x1 +#define MP_IRQ_POLARITY_LOW 0x3 +#define MP_IRQ_POLARITY_MASK 0x3 +#define MP_IRQ_TRIGGER_DEFAULT 0x0 +#define MP_IRQ_TRIGGER_EDGE 0x4 +#define MP_IRQ_TRIGGER_LEVEL 0xc +#define MP_IRQ_TRIGGER_MASK 0xc + +#define ACTL 0x00 +#define SCIS_MASK 0x07 +#define SCIS_IRQ9 0x00 +#define SCIS_IRQ10 0x01 +#define SCIS_IRQ11 0x02 +#define SCIS_IRQ20 0x04 +#define SCIS_IRQ21 0x05 +#define SCIS_IRQ22 0x06 +#define SCIS_IRQ23 0x07 + +enum acpi_bus_type { + PIC = 0, + APIC = 2, + ETHIGH = 5 +}; + +#define ACPI_REV_ACPI_1_0 1 +#define ACPI_REV_ACPI_2_0 1 +#define ACPI_REV_ACPI_3_0 2 +#define ACPI_REV_ACPI_4_0 3 +#define ACPI_REV_ACPI_5_0 5 + +#define ACPI_RSDP_REV_ACPI_1_0 0 +#define ACPI_RSDP_REV_ACPI_2_0 2 + +typedef struct acpi_gen_regaddr { + u8 space_id; /* Address space ID */ + u8 bit_width; /* Register size in bits */ + u8 bit_offset; /* Register bit offset */ + union { + /* Reserved in ACPI 2.0 - 2.0b */ + u8 resv; + /* Access size in ACPI 2.0c/3.0/4.0/5.0 */ + u8 access_size; + }; + u32 addrl; /* Register address, low 32 bits */ + u32 addrh; /* Register address, high 32 bits */ +} acpi_addr_t; + + +/* RSDP (Root System Description Pointer) +Note: ACPI 1.0 didn't have length, xsdt_address, and ext_checksum. */ +struct acpi_rsdp { + char signature[8]; /* RSDP signature */ + u8 checksum; /* Checksum of the first 20 bytes */ + char oem_id[6]; /* OEM ID */ + u8 revision; /* 0 for ACPI 1.0, 2 for ACPI 2.0/3.0/4.0 */ + u32 rsdt_address; /* Physical address of RSDT (32 bits) */ + u32 length; /* Total RSDP length (incl. extended part) */ + u64 xsdt_address; /* Physical address of XSDT (64 bits) */ + u8 ext_checksum; /* Checksum of the whole table */ + u8 reserved[3]; +}; + +enum acpi_address_space_type { + ACPI_ADDRESS_SPACE_MEMORY = 0, /* System memory */ + ACPI_ADDRESS_SPACE_IO = 1, /* System I/O */ + ACPI_ADDRESS_SPACE_PCI = 2, /* PCI config space */ + ACPI_ADDRESS_SPACE_EC = 3, /* Embedded controller */ + ACPI_ADDRESS_SPACE_SMBUS = 4, /* SMBus */ + ACPI_ADDRESS_SPACE_PCC = 0x0a, /* Platform Comm. Channel */ + ACPI_ADDRESS_SPACE_FIXED = 0x7f /* Functional fixed hardware */ +}; + +#define ACPI_FFIXEDHW_VENDOR_INTEL 1 /* Intel */ +#define ACPI_FFIXEDHW_CLASS_HLT 0 /* C1 Halt */ +#define ACPI_FFIXEDHW_CLASS_IO_HLT 1 /* C1 I/O then Halt */ +#define ACPI_FFIXEDHW_CLASS_MWAIT 2 /* MWAIT Native C-state */ +#define ACPI_FFIXEDHW_FLAG_HW_COORD 1 /* Hardware Coordination bit */ +#define ACPI_FFIXEDHW_FLAG_BM_STS 2 /* BM_STS avoidance bit */ + +/* Access size definitions for Generic address structure */ +enum acpi_address_space_size { + ACPI_ACCESS_SIZE_UNDEFINED = 0, /* Undefined (legacy reasons) */ + ACPI_ACCESS_SIZE_BYTE_ACCESS = 1, + ACPI_ACCESS_SIZE_WORD_ACCESS = 2, + ACPI_ACCESS_SIZE_DWORD_ACCESS = 3, + ACPI_ACCESS_SIZE_QWORD_ACCESS = 4 +}; + +/* Generic ACPI header, provided by (almost) all tables */ +typedef struct acpi_table_header { + char signature[4]; /* ACPI signature (4 ASCII characters) */ + u32 length; /* Table length in bytes (incl. header) */ + u8 revision; /* Table version (not ACPI version!) */ + volatile u8 checksum; /* To make sum of entire table == 0 */ + char oem_id[6]; /* OEM identification */ + char oem_table_id[8]; /* OEM table identification */ + u32 oem_revision; /* OEM revision number */ + char asl_compiler_id[4]; /* ASL compiler vendor ID */ + u32 asl_compiler_revision; /* ASL compiler revision number */ +} acpi_header_t; + +/* A maximum number of 32 ACPI tables ought to be enough for now. */ +#define MAX_ACPI_TABLES 32 + +/* RSDT (Root System Description Table) */ +struct acpi_rsdt { + struct acpi_table_header header; + u32 entry[MAX_ACPI_TABLES]; +}; + +/* XSDT (Extended System Description Table) */ +struct acpi_xsdt { + struct acpi_table_header header; + u64 entry[MAX_ACPI_TABLES]; +}; + +/* MCFG (PCI Express MMIO config space BAR description table) */ +struct acpi_mcfg { + struct acpi_table_header header; + u8 reserved[8]; +}; + +struct acpi_mcfg_mmconfig { + u32 base_address; + u32 base_reserved; + u16 pci_segment_group_number; + u8 start_bus_number; + u8 end_bus_number; + u8 reserved[4]; +}; + +/* MADT (Multiple APIC Description Table) */ +struct acpi_madt { + struct acpi_table_header header; + u32 lapic_addr; /* Local APIC address */ + u32 flags; /* Multiple APIC flags */ +} acpi_madt_t; + +enum dev_scope_type { + SCOPE_PCI_ENDPOINT = 1, + SCOPE_PCI_SUB = 2, + SCOPE_IOAPIC = 3, + SCOPE_MSI_HPET = 4 +}; + +typedef struct dev_scope { + u8 type; + u8 length; + u8 reserved[2]; + u8 enumeration; + u8 start_bus; + struct { + u8 dev; + u8 fn; + } path[0]; +} __packed dev_scope_t; + +/* MADT: APIC Structure Type*/ +enum acpi_apic_types { + LOCALAPIC = 0, /* Processor local APIC */ + IOAPIC = 1, /* I/O APIC */ + IRQSOURCEOVERRIDE = 2, /* Interrupt source override */ + NMITYPE = 3, /* NMI source */ + LOCALNMITYPE = 4, /* Local APIC NMI */ + LAPICADDRESSOVERRIDE = 5, /* Local APIC address override */ + IOSAPIC = 6, /* I/O SAPIC */ + LOCALSAPIC = 7, /* Local SAPIC */ + PLATFORMIRQSOURCES = 8, /* Platform interrupt sources */ + LOCALX2SAPIC = 9, /* Processor local x2APIC */ + LOCALX2APICNMI = 10, /* Local x2APIC NMI */ +}; + +/* MADT: Processor Local APIC Structure */ +struct acpi_madt_lapic { + u8 type; /* Type (0) */ + u8 length; /* Length in bytes (8) */ + u8 processor_id; /* ACPI processor ID */ + u8 apic_id; /* Local APIC ID */ + u32 flags; /* Local APIC flags */ +}; + +#define LOCAL_APIC_FLAG_ENABLED (1 << 0) +/* bits 1-31: reserved */ +#define PCAT_COMPAT (1 << 0) +/* bits 1-31: reserved */ + +/* MADT: Local APIC NMI Structure */ +struct acpi_madt_lapic_nmi { + u8 type; /* Type (4) */ + u8 length; /* Length in bytes (6) */ + u8 processor_id; /* ACPI processor ID */ + u16 flags; /* MPS INTI flags */ + u8 lint; /* Local APIC LINT# */ +}; + +/* MADT: I/O APIC Structure */ +struct acpi_madt_ioapic { + u8 type; /* Type (1) */ + u8 length; /* Length in bytes (12) */ + u8 ioapic_id; /* I/O APIC ID */ + u8 reserved; + u32 ioapic_addr; /* I/O APIC address */ + u32 gsi_base; /* Global system interrupt base */ +}; + +/* MADT: Interrupt Source Override Structure */ +struct acpi_madt_irqoverride { + u8 type; /* Type (2) */ + u8 length; /* Length in bytes (10) */ + u8 bus; /* ISA (0) */ + u8 source; /* Bus-relative int. source (IRQ) */ + u32 gsirq; /* Global system interrupt */ + u16 flags; /* MPS INTI flags */ +}; + +/* FADT (Fixed ACPI Description Table) */ +struct __packed acpi_fadt { + struct acpi_table_header header; + u32 firmware_ctrl; + u32 dsdt; + u8 model; + u8 preferred_pm_profile; + u16 sci_int; + u32 smi_cmd; + u8 acpi_enable; + u8 acpi_disable; + u8 s4bios_req; + u8 pstate_cnt; + u32 pm1a_evt_blk; + u32 pm1b_evt_blk; + u32 pm1a_cnt_blk; + u32 pm1b_cnt_blk; + u32 pm2_cnt_blk; + u32 pm_tmr_blk; + u32 gpe0_blk; + u32 gpe1_blk; + u8 pm1_evt_len; + u8 pm1_cnt_len; + u8 pm2_cnt_len; + u8 pm_tmr_len; + u8 gpe0_blk_len; + u8 gpe1_blk_len; + u8 gpe1_base; + u8 cst_cnt; + u16 p_lvl2_lat; + u16 p_lvl3_lat; + u16 flush_size; + u16 flush_stride; + u8 duty_offset; + u8 duty_width; + u8 day_alrm; + u8 mon_alrm; + u8 century; + u16 iapc_boot_arch; + u8 res2; + u32 flags; + struct acpi_gen_regaddr reset_reg; + u8 reset_value; + u8 res3; + u8 res4; + u8 res5; + u32 x_firmware_ctl_l; + u32 x_firmware_ctl_h; + u32 x_dsdt_l; + u32 x_dsdt_h; + struct acpi_gen_regaddr x_pm1a_evt_blk; + struct acpi_gen_regaddr x_pm1b_evt_blk; + struct acpi_gen_regaddr x_pm1a_cnt_blk; + struct acpi_gen_regaddr x_pm1b_cnt_blk; + struct acpi_gen_regaddr x_pm2_cnt_blk; + struct acpi_gen_regaddr x_pm_tmr_blk; + struct acpi_gen_regaddr x_gpe0_blk; + struct acpi_gen_regaddr x_gpe1_blk; +}; + +/* Flags for p_lvl2_lat and p_lvl3_lat */ +#define ACPI_FADT_C2_NOT_SUPPORTED 101 +#define ACPI_FADT_C3_NOT_SUPPORTED 1001 + +/* FADT Feature Flags */ +#define ACPI_FADT_WBINVD (1 << 0) +#define ACPI_FADT_WBINVD_FLUSH (1 << 1) +#define ACPI_FADT_C1_SUPPORTED (1 << 2) +#define ACPI_FADT_C2_MP_SUPPORTED (1 << 3) +#define ACPI_FADT_POWER_BUTTON (1 << 4) +#define ACPI_FADT_SLEEP_BUTTON (1 << 5) +#define ACPI_FADT_FIXED_RTC (1 << 6) +#define ACPI_FADT_S4_RTC_WAKE (1 << 7) +#define ACPI_FADT_32BIT_TIMER (1 << 8) +#define ACPI_FADT_DOCKING_SUPPORTED (1 << 9) +#define ACPI_FADT_RESET_REGISTER (1 << 10) +#define ACPI_FADT_SEALED_CASE (1 << 11) +#define ACPI_FADT_HEADLESS (1 << 12) +#define ACPI_FADT_SLEEP_TYPE (1 << 13) +#define ACPI_FADT_PCI_EXPRESS_WAKE (1 << 14) +#define ACPI_FADT_PLATFORM_CLOCK (1 << 15) +#define ACPI_FADT_S4_RTC_VALID (1 << 16) +#define ACPI_FADT_REMOTE_POWER_ON (1 << 17) +#define ACPI_FADT_APIC_CLUSTER (1 << 18) +#define ACPI_FADT_APIC_PHYSICAL (1 << 19) +/* Bits 20-31: reserved ACPI 3.0 & 4.0 */ +#define ACPI_FADT_HW_REDUCED_ACPI (1 << 20) +#define ACPI_FADT_LOW_PWR_IDLE_S0 (1 << 21) +/* bits 22-31: reserved ACPI 5.0 */ + +/* FADT Boot Architecture Flags */ +#define ACPI_FADT_LEGACY_DEVICES (1 << 0) +#define ACPI_FADT_8042 (1 << 1) +#define ACPI_FADT_VGA_NOT_PRESENT (1 << 2) +#define ACPI_FADT_MSI_NOT_SUPPORTED (1 << 3) +#define ACPI_FADT_NO_PCIE_ASPM_CONTROL (1 << 4) +#define ACPI_FADT_LEGACY_FREE 0x00 /* No legacy devices (including 8042) */ + +/* FADT Preferred Power Management Profile */ +#define PM_UNSPECIFIED 0 +#define PM_DESKTOP 1 +#define PM_MOBILE 2 +#define PM_WORKSTATION 3 +#define PM_ENTERPRISE_SERVER 4 +#define PM_SOHO_SERVER 5 +#define PM_APPLIANCE_PC 6 +#define PM_PERFORMANCE_SERVER 7 +#define PM_TABLET 8, /* ACPI 5.0 */ + +/* FACS (Firmware ACPI Control Structure) */ +struct acpi_facs { + char signature[4]; /* "FACS" */ + u32 length; /* Length in bytes (>= 64) */ + u32 hardware_signature; /* Hardware signature */ + u32 firmware_waking_vector; /* Firmware waking vector */ + u32 global_lock; /* Global lock */ + u32 flags; /* FACS flags */ + u32 x_firmware_waking_vector_l; /* X FW waking vector, low */ + u32 x_firmware_waking_vector_h; /* X FW waking vector, high */ + u8 version; /* ACPI 4.0: 2 */ + u8 resv[31]; /* FIXME: 4.0: ospm_flags */ +}; + +/* FACS flags */ +#define ACPI_FACS_S4BIOS_F (1 << 0) +#define ACPI_FACS_64BIT_WAKE_F (1 << 1) +/* Bits 31..2: reserved */ + +/* These can be used by the target port. */ + +unsigned long acpi_create_madt_lapics(unsigned long current); +int acpi_create_madt_ioapic(struct acpi_madt_ioapic *ioapic, u8 id, u32 addr, + u32 gsi_base); +int acpi_create_madt_irqoverride(struct acpi_madt_irqoverride *irqoverride, + u8 bus, u8 source, u32 gsirq, u16 flags); +unsigned long acpi_fill_madt(unsigned long current); +void acpi_create_fadt(struct acpi_fadt *fadt, struct acpi_facs *facs, + void *dsdt); +int acpi_create_madt_lapic_nmi(struct acpi_madt_lapic_nmi *lapic_nmi, u8 cpu, + u16 flags, u8 lint); +unsigned long write_acpi_tables(unsigned long start); + diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index dcfe9ee..6ecd6db 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -30,6 +30,7 @@ obj-y += physmem.o obj-$(CONFIG_X86_RAMTEST) += ramtest.o obj-y += sfi.o obj-y += string.o +obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o obj-y += tables.o obj-$(CONFIG_SYS_X86_TSC_TIMER) += tsc_timer.o obj-$(CONFIG_CMD_ZBOOT) += zimage.o diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c new file mode 100644 index 0000000..bd880ea --- /dev/null +++ b/arch/x86/lib/acpi_table.c @@ -0,0 +1,433 @@ +/* + * Based on acpi.c from coreboot + * + * Copyright (C) 2015, Saket Sinha saket.sinha89@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <cpu.h> +#include <dm.h> +#include <dm/uclass-internal.h> +#include <dm/lists.h> +#include <asm/acpi_table.h> +#include <asm/cpu.h> +#include <asm/ioapic.h> +#include <asm/lapic.h> +#include <asm/tables.h> +#include <asm/pci.h> + + +extern const unsigned char AmlCode[]; + +/** +* Add an ACPI table to the RSDT (and XSDT) structure, recalculate length +* and checksum. +*/ +static void acpi_add_table(struct acpi_rsdp *rsdp, void *table) +{ + int i, entries_num; + struct acpi_rsdt *rsdt; + struct acpi_xsdt *xsdt = NULL; + + /* The RSDT is mandatory while the XSDT is not */ + rsdt = (struct acpi_rsdt *)rsdp->rsdt_address; + + if (rsdp->xsdt_address) + xsdt = (struct acpi_xsdt *)((u32)rsdp->xsdt_address); + + /* This should always be MAX_ACPI_TABLES */ + entries_num = ARRAY_SIZE(rsdt->entry); + + for (i = 0; i < entries_num; i++) { + if (rsdt->entry[i] == 0) + break; + } + + if (i >= entries_num) { + debug("ACPI: Error: too many tables.\n"); + return; + } + + /* Add table to the RSDT */ + rsdt->entry[i] = (u32)table; + + /* Fix RSDT length or the kernel will assume invalid entries */ + rsdt->header.length = sizeof(acpi_header_t) + (sizeof(u32) * (i + 1)); + + /* Re-calculate checksum. */ + rsdt->header.checksum = 0; + rsdt->header.checksum = table_compute_checksum((u8 *)rsdt, + rsdt->header.length); + + /* + * And now the same thing for the XSDT. We use the same index as for + * now we want the XSDT and RSDT to always be in sync in uboot + */ + if (xsdt) { + /* Add table to the XSDT */ + xsdt->entry[i] = (u64)(u32)table; + + /* Fix XSDT length */ + xsdt->header.length = sizeof(acpi_header_t) + + (sizeof(u64) * (i + 1)); + + /* Re-calculate checksum */ + xsdt->header.checksum = 0; + xsdt->header.checksum = table_compute_checksum((u8 *)xsdt, + xsdt->header.length); + } +} + +static int acpi_create_madt_lapic(struct acpi_madt_lapic *lapic, + u8 cpu, u8 apic) +{ + lapic->type = LOCALAPIC; /* Local APIC structure */ + lapic->length = sizeof(struct acpi_madt_lapic); + lapic->flags = LOCAL_APIC_FLAG_ENABLED; /* Processor/LAPIC enabled */ + lapic->processor_id = cpu; + lapic->apic_id = apic; + + return lapic->length; +} + +unsigned long acpi_create_madt_lapics(unsigned long current) +{ + struct udevice *dev; + + for (uclass_find_first_device(UCLASS_CPU, &dev); + dev; + uclass_find_next_device(&dev)) { + struct cpu_platdata *plat = dev_get_parent_platdata(dev); + + current += acpi_create_madt_lapic + ((struct acpi_madt_lapic *)current, + plat->cpu_id, plat->cpu_id); + } + return current; +} + +int acpi_create_madt_ioapic(struct acpi_madt_ioapic *ioapic, u8 id, u32 addr, + u32 gsi_base) +{ + ioapic->type = IOAPIC; + ioapic->length = sizeof(struct acpi_madt_ioapic); + ioapic->reserved = 0x00; + ioapic->gsi_base = gsi_base; + ioapic->ioapic_id = id; + ioapic->ioapic_addr = addr; + + return ioapic->length; +} + +int acpi_create_madt_irqoverride(struct acpi_madt_irqoverride *irqoverride, + u8 bus, u8 source, u32 gsirq, u16 flags) +{ + irqoverride->type = IRQSOURCEOVERRIDE; + irqoverride->length = sizeof(struct acpi_madt_irqoverride); + irqoverride->bus = bus; + irqoverride->source = source; + irqoverride->gsirq = gsirq; + irqoverride->flags = flags; + + return irqoverride->length; +} + +int acpi_create_madt_lapic_nmi(struct acpi_madt_lapic_nmi *lapic_nmi, + u8 cpu, u16 flags, u8 lint) +{ + lapic_nmi->type = LOCALNMITYPE; + lapic_nmi->length = sizeof(struct acpi_madt_lapic_nmi); + lapic_nmi->flags = flags; + lapic_nmi->processor_id = cpu; + lapic_nmi->lint = lint; + + return lapic_nmi->length; +} + +static void fill_header(acpi_header_t *header, char *signature, int length) +{ + memcpy(header->signature, signature, length); + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); + memcpy(header->asl_compiler_id, ASLC, 4); +} + +static void acpi_create_madt(struct acpi_madt *madt) +{ + acpi_header_t *header = &(madt->header); + unsigned long current = (unsigned long)madt + sizeof(struct acpi_madt); + + memset((void *)madt, 0, sizeof(struct acpi_madt)); + + /* Fill out header fields. */ + fill_header(header, "APIC", 4); + header->length = sizeof(struct acpi_madt); + + /* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */ + header->revision = ACPI_REV_ACPI_2_0; + + madt->lapic_addr = LAPIC_DEFAULT_BASE; + madt->flags = PCAT_COMPAT; + + current = acpi_fill_madt(current); + + /* (Re)calculate length and checksum */ + header->length = current - (unsigned long)madt; + + header->checksum = table_compute_checksum((void *)madt, header->length); +} + +static int acpi_create_mcfg_mmconfig(struct acpi_mcfg_mmconfig *mmconfig, + u32 base, u16 seg_nr, u8 start, u8 end) +{ + memset(mmconfig, 0, sizeof(*mmconfig)); + mmconfig->base_address = base; + mmconfig->base_reserved = 0; + mmconfig->pci_segment_group_number = seg_nr; + mmconfig->start_bus_number = start; + mmconfig->end_bus_number = end; + + return sizeof(struct acpi_mcfg_mmconfig); +} + +static unsigned long acpi_fill_mcfg(unsigned long current) +{ + current += acpi_create_mcfg_mmconfig + ((struct acpi_mcfg_mmconfig *)current, + CONFIG_PCIE_ECAM_BASE, 0x0, 0x0, 255); + + return current; +} + +/* MCFG is defined in the PCI Firmware Specification 3.0 */ +static void acpi_create_mcfg(struct acpi_mcfg *mcfg) +{ + acpi_header_t *header = &(mcfg->header); + unsigned long current = (unsigned long)mcfg + sizeof(struct acpi_mcfg); + + memset((void *)mcfg, 0, sizeof(struct acpi_mcfg)); + + /* Fill out header fields */ + fill_header(header, "MCFG", 4); + header->length = sizeof(struct acpi_mcfg); + + /* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */ + header->revision = ACPI_REV_ACPI_2_0; + + current = acpi_fill_mcfg(current); + + /* (Re)calculate length and checksum */ + header->length = current - (unsigned long)mcfg; + header->checksum = table_compute_checksum((void *)mcfg, header->length); +} + +static void acpi_create_facs(struct acpi_facs *facs) +{ + memset((void *)facs, 0, sizeof(struct acpi_facs)); + + memcpy(facs->signature, "FACS", 4); + facs->length = sizeof(struct acpi_facs); + facs->hardware_signature = 0; + facs->firmware_waking_vector = 0; + facs->global_lock = 0; + facs->flags = 0; + facs->x_firmware_waking_vector_l = 0; + facs->x_firmware_waking_vector_h = 0; + facs->version = 1; /* ACPI 1.0: 0, ACPI 2.0/3.0: 1, ACPI 4.0: 2 */ +} + +static void acpi_write_rsdt(struct acpi_rsdt *rsdt) +{ + acpi_header_t *header = &(rsdt->header); + + /* Fill out header fields */ + fill_header(header, "RSDT", 4); + header->length = sizeof(struct acpi_rsdt); + + /* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */ + header->revision = ACPI_REV_ACPI_2_0; + + /* Entries are filled in later, we come with an empty set */ + + /* Fix checksum */ + header->checksum = table_compute_checksum((void *)rsdt, + sizeof(struct acpi_rsdt)); +} + +static void acpi_write_xsdt(struct acpi_xsdt *xsdt) +{ + acpi_header_t *header = &(xsdt->header); + + /* Fill out header fields */ + fill_header(header, "XSDT", 4); + header->length = sizeof(struct acpi_xsdt); + + /* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */ + header->revision = ACPI_REV_ACPI_2_0; + + /* Entries are filled in later, we come with an empty set */ + + /* Fix checksum */ + header->checksum = table_compute_checksum((void *)xsdt, + sizeof(struct acpi_xsdt)); +} + +static void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt, + struct acpi_xsdt *xsdt) +{ + memset(rsdp, 0, sizeof(struct acpi_rsdp)); + + memcpy(rsdp->signature, RSDP_SIG, 8); + memcpy(rsdp->oem_id, OEM_ID, 6); + + rsdp->length = sizeof(struct acpi_rsdp); + rsdp->rsdt_address = (u32)rsdt; + + /* + * Revision: ACPI 1.0: 0, ACPI 2.0/3.0/4.0: 2 + * + * Some OSes expect an XSDT to be present for RSD PTR revisions >= 2. + * If we don't have an ACPI XSDT, force ACPI 1.0 (and thus RSD PTR + * revision 0) + */ + if (xsdt == NULL) { + rsdp->revision = ACPI_RSDP_REV_ACPI_1_0; + } else { + rsdp->xsdt_address = (u64)(u32)xsdt; + rsdp->revision = ACPI_RSDP_REV_ACPI_2_0; + } + + /* Calculate checksums */ + rsdp->checksum = table_compute_checksum((void *)rsdp, 20); + rsdp->ext_checksum = table_compute_checksum((void *)rsdp, + sizeof(struct acpi_rsdp)); +} + +static void acpi_create_ssdt_generator(acpi_header_t *ssdt, + const char *oem_table_id) +{ + unsigned long current = (unsigned long)ssdt + sizeof(acpi_header_t); + + memset((void *)ssdt, 0, sizeof(acpi_header_t)); + + memcpy(&ssdt->signature, "SSDT", 4); + /* Access size in ACPI 2.0c/3.0/4.0/5.0 */ + ssdt->revision = ACPI_REV_ACPI_3_0; + memcpy(&ssdt->oem_id, OEM_ID, 6); + memcpy(&ssdt->oem_table_id, oem_table_id, 8); + ssdt->oem_revision = OEM_REVISION; + memcpy(&ssdt->asl_compiler_id, ASLC, 4); + ssdt->asl_compiler_revision = ASL_COMPILER_REVISION; + ssdt->length = sizeof(acpi_header_t); + + /* (Re)calculate length and checksum */ + ssdt->length = current - (unsigned long)ssdt; + ssdt->checksum = table_compute_checksum((void *)ssdt, ssdt->length); +} + +unsigned long write_acpi_tables(unsigned long start) +{ + unsigned long current; + struct acpi_rsdp *rsdp; + struct acpi_rsdt *rsdt; + struct acpi_xsdt *xsdt; + struct acpi_facs *facs; + acpi_header_t *dsdt; + struct acpi_fadt *fadt; + struct acpi_mcfg *mcfg; + struct acpi_madt *madt; + acpi_header_t *ssdt; + + current = start; + + /* Align ACPI tables to 16byte */ + current = (ALIGN(current, 16)); + + debug("ACPI: Writing ACPI tables at %lx.\n", start); + + /* We need at least an RSDP and an RSDT Table */ + rsdp = (struct acpi_rsdp *)current; + current += sizeof(struct acpi_rsdp); + current = (ALIGN(current, 16)); + rsdt = (struct acpi_rsdt *)current; + current += sizeof(struct acpi_rsdt); + current = (ALIGN(current, 16)); + xsdt = (struct acpi_xsdt *)current; + current += sizeof(struct acpi_xsdt); + current = (ALIGN(current, 16)); + + /* clear all table memory */ + memset((void *)start, 0, current - start); + + acpi_write_rsdp(rsdp, rsdt, xsdt); + acpi_write_rsdt(rsdt); + acpi_write_xsdt(xsdt); + + debug("ACPI: * FACS\n"); + facs = (struct acpi_facs *)current; + current += sizeof(struct acpi_facs); + current = (ALIGN(current, 16)); + + acpi_create_facs(facs); + + debug("ACPI: * DSDT\n"); + dsdt = (acpi_header_t *)current; + memcpy(dsdt, &AmlCode, sizeof(acpi_header_t)); + if (dsdt->length >= sizeof(acpi_header_t)) { + current += sizeof(acpi_header_t); + memcpy((char *)current, + (char *)&AmlCode + sizeof(acpi_header_t), + dsdt->length - sizeof(acpi_header_t)); + current += dsdt->length - sizeof(acpi_header_t); + + /* (Re)calculate length and checksum */ + dsdt->length = current - (unsigned long)dsdt; + dsdt->checksum = 0; + dsdt->checksum = table_compute_checksum((void *)dsdt, + dsdt->length); + } + current = (ALIGN(current, 16)); + + debug("ACPI: * FADT\n"); + fadt = (struct acpi_fadt *)current; + current += sizeof(struct acpi_fadt); + current = (ALIGN(current, 16)); + acpi_create_fadt(fadt, facs, dsdt); + acpi_add_table(rsdp, fadt); + + debug("ACPI: * MCFG\n"); + mcfg = (struct acpi_mcfg *)current; + acpi_create_mcfg(mcfg); + if (mcfg->header.length > sizeof(struct acpi_mcfg)) { + current += mcfg->header.length; + current = (ALIGN(current, 16)); + acpi_add_table(rsdp, mcfg); + } + + debug("ACPI: * MADT\n"); + madt = (struct acpi_madt *)current; + acpi_create_madt(madt); + if (madt->header.length > sizeof(struct acpi_madt)) { + current += madt->header.length; + acpi_add_table(rsdp, madt); + } + current = (ALIGN(current, 16)); + + debug("ACPI: * SSDT\n"); + ssdt = (acpi_header_t *)current; + acpi_create_ssdt_generator(ssdt, ACPI_TABLE_CREATOR); + if (ssdt->length > sizeof(acpi_header_t)) { + current += ssdt->length; + acpi_add_table(rsdp, ssdt); + current = (ALIGN(current, 16)); + } + + + debug("current = %lx\n", current); + + debug("ACPI: done.\n"); + return current; +} + diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c index 75ffbc1..f15b2e2 100644 --- a/arch/x86/lib/tables.c +++ b/arch/x86/lib/tables.c @@ -8,6 +8,7 @@ #include <asm/sfi.h> #include <asm/mpspec.h> #include <asm/tables.h> +#include <asm/acpi_table.h>
u8 table_compute_checksum(void *v, int len) { @@ -51,4 +52,8 @@ void write_tables(void) rom_table_end = write_mp_table(rom_table_end); rom_table_end = ALIGN(rom_table_end, 1024); #endif +#ifdef CONFIG_GENERATE_ACPI_TABLE + rom_table_end = write_acpi_tables(rom_table_end); + rom_table_end = ALIGN(rom_table_end, 1024); +#endif } diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 1c949fc..ed30bf5 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -297,6 +297,17 @@ $(obj)/%.dtb: $(src)/%.dts FORCE
dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp)
+# ACPI +# --------------------------------------------------------------------------- +quiet_cmd_acpi_c_asl= ASL $@ +cmd_acpi_c_asl= \ + $(CPP) -x assembler-with-cpp -P -o $<.tmp $<; \ + iasl -p $< -tc -va $<.tmp; \ + mv $(patsubst %.asl,%.hex,$<) $@ + +$(obj)/%.c: $(src)/%.asl + $(call cmd,acpi_c_asl) + # Bzip2 # ---------------------------------------------------------------------------

Hi Saket,
On Tue, Aug 18, 2015 at 3:29 AM, Saket Sinha saket.sinha89@gmail.com wrote:
Implement write_acpi_table() to create a minimal working ACPI table. This includes writing FACS, XSDT, RSDP, FADT, MCFG, MADT, DSDT & SSDT ACPI table entries.
Use a Kconfig option GENERATE_ACPI_TABLE to tell U-Boot whether we need actually write the APCI table just like we did for PIRQ routing, MP table and SFI tables. With ACPI table existence, linux kernel gets control of power management, thermal management, configuration management and monitoring in hardware.
Nice write-up!
Signed-off-by: Saket Sinha saket.sinha89@gmail.com
arch/x86/Kconfig | 9 + arch/x86/include/asm/acpi_table.h | 390 ++++++++++++++++++++++++++++++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/acpi_table.c | 433 ++++++++++++++++++++++++++++++++++++++ arch/x86/lib/tables.c | 5 + scripts/Makefile.lib | 11 + 6 files changed, 849 insertions(+) create mode 100644 arch/x86/include/asm/acpi_table.h create mode 100644 arch/x86/lib/acpi_table.c
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 01ed760..ae881a1 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -344,6 +344,15 @@ config GENERATE_MP_TABLE multiprocessing as well as symmetric I/O interrupt handling with the local APIC and I/O APIC.
+config GENERATE_ACPI_TABLE
bool "Generate an ACPI (Advanced Configuration and Power Interface) table"
default n
help
The Advanced Configuration and Power Interface (ACPI) specification
provides an open standard for device configuration and management
by the operating system. It defines platform-independent interfaces
for configuration and power management monitoring.
endmenu
config MAX_PIRQ_LINKS diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h new file mode 100644 index 0000000..a813a0a --- /dev/null +++ b/arch/x86/include/asm/acpi_table.h @@ -0,0 +1,390 @@ +/*
- Based on acpi.c from coreboot
- Copyright (C) 2015, Saket Sinha saket.sinha89@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <malloc.h> +#include <asm/post.h> +#include <linux/string.h>
+#define RSDP_SIG "RSD PTR " /* RSDT pointer signature */ +#define ACPI_TABLE_CREATOR "UBOOT " /* Must be exactly 8 bytes long! */ +#define OEM_ID "UBOOT " /* Must be exactly 6 bytes long! */ +#define ASLC "INTL" /* Must be exactly 4 bytes long! */
Nits: could we use tab to between macro names, value and comments?
+#define OEM_REVISION 42 +#define ASL_COMPILER_REVISION 42
ditto
+#define APM_CNT 0xb2 +#define APM_CNT_CST_CONTROL 0x85 +#define APM_CNT_PST_CONTROL 0x80 +#define APM_CNT_ACPI_DISABLE 0x1e +#define APM_CNT_ACPI_ENABLE 0xe1 +#define APM_CNT_MBI_UPDATE 0xeb +#define APM_CNT_GNVS_UPDATE 0xea +#define APM_CNT_FINALIZE 0xcb +#define APM_CNT_LEGACY 0xcc +#define APM_ST 0xb3
ditto, and can you add some comments on what these are?
+#define MP_IRQ_POLARITY_DEFAULT 0x0 +#define MP_IRQ_POLARITY_HIGH 0x1 +#define MP_IRQ_POLARITY_LOW 0x3 +#define MP_IRQ_POLARITY_MASK 0x3 +#define MP_IRQ_TRIGGER_DEFAULT 0x0 +#define MP_IRQ_TRIGGER_EDGE 0x4 +#define MP_IRQ_TRIGGER_LEVEL 0xc +#define MP_IRQ_TRIGGER_MASK 0xc
ditto, and can you add some comments on what these are?
+#define ACTL 0x00 +#define SCIS_MASK 0x07 +#define SCIS_IRQ9 0x00 +#define SCIS_IRQ10 0x01 +#define SCIS_IRQ11 0x02 +#define SCIS_IRQ20 0x04 +#define SCIS_IRQ21 0x05 +#define SCIS_IRQ22 0x06 +#define SCIS_IRQ23 0x07
ditto, and can you add some comments on what these are?
+enum acpi_bus_type {
PIC = 0,
APIC = 2,
ETHIGH = 5
+};
I remember I pointed this out in previous version that the name of PIC, APIC is too generic.
+#define ACPI_REV_ACPI_1_0 1 +#define ACPI_REV_ACPI_2_0 1 +#define ACPI_REV_ACPI_3_0 2 +#define ACPI_REV_ACPI_4_0 3 +#define ACPI_REV_ACPI_5_0 5
+#define ACPI_RSDP_REV_ACPI_1_0 0 +#define ACPI_RSDP_REV_ACPI_2_0 2
+typedef struct acpi_gen_regaddr {
u8 space_id; /* Address space ID */
u8 bit_width; /* Register size in bits */
u8 bit_offset; /* Register bit offset */
union {
/* Reserved in ACPI 2.0 - 2.0b */
u8 resv;
/* Access size in ACPI 2.0c/3.0/4.0/5.0 */
u8 access_size;
};
u32 addrl; /* Register address, low 32 bits */
u32 addrh; /* Register address, high 32 bits */
+} acpi_addr_t;
+/* RSDP (Root System Description Pointer) +Note: ACPI 1.0 didn't have length, xsdt_address, and ext_checksum. */
Please use multi-line comment format. Please fix this globally (I think I pointed this out in previous review)
+struct acpi_rsdp {
char signature[8]; /* RSDP signature */
u8 checksum; /* Checksum of the first 20 bytes */
char oem_id[6]; /* OEM ID */
u8 revision; /* 0 for ACPI 1.0, 2 for ACPI 2.0/3.0/4.0 */
u32 rsdt_address; /* Physical address of RSDT (32 bits) */
u32 length; /* Total RSDP length (incl. extended part) */
u64 xsdt_address; /* Physical address of XSDT (64 bits) */
u8 ext_checksum; /* Checksum of the whole table */
u8 reserved[3];
+};
+enum acpi_address_space_type {
ACPI_ADDRESS_SPACE_MEMORY = 0, /* System memory */
ACPI_ADDRESS_SPACE_IO = 1, /* System I/O */
ACPI_ADDRESS_SPACE_PCI = 2, /* PCI config space */
ACPI_ADDRESS_SPACE_EC = 3, /* Embedded controller */
ACPI_ADDRESS_SPACE_SMBUS = 4, /* SMBus */
ACPI_ADDRESS_SPACE_PCC = 0x0a, /* Platform Comm. Channel */
ACPI_ADDRESS_SPACE_FIXED = 0x7f /* Functional fixed hardware */
+};
+#define ACPI_FFIXEDHW_VENDOR_INTEL 1 /* Intel */ +#define ACPI_FFIXEDHW_CLASS_HLT 0 /* C1 Halt */ +#define ACPI_FFIXEDHW_CLASS_IO_HLT 1 /* C1 I/O then Halt */ +#define ACPI_FFIXEDHW_CLASS_MWAIT 2 /* MWAIT Native C-state */ +#define ACPI_FFIXEDHW_FLAG_HW_COORD 1 /* Hardware Coordination bit */ +#define ACPI_FFIXEDHW_FLAG_BM_STS 2 /* BM_STS avoidance bit */
+/* Access size definitions for Generic address structure */ +enum acpi_address_space_size {
ACPI_ACCESS_SIZE_UNDEFINED = 0, /* Undefined (legacy reasons) */
ACPI_ACCESS_SIZE_BYTE_ACCESS = 1,
ACPI_ACCESS_SIZE_WORD_ACCESS = 2,
ACPI_ACCESS_SIZE_DWORD_ACCESS = 3,
ACPI_ACCESS_SIZE_QWORD_ACCESS = 4
+};
+/* Generic ACPI header, provided by (almost) all tables */ +typedef struct acpi_table_header {
char signature[4]; /* ACPI signature (4 ASCII characters) */
u32 length; /* Table length in bytes (incl. header) */
u8 revision; /* Table version (not ACPI version!) */
volatile u8 checksum; /* To make sum of entire table == 0 */
char oem_id[6]; /* OEM identification */
char oem_table_id[8]; /* OEM table identification */
u32 oem_revision; /* OEM revision number */
char asl_compiler_id[4]; /* ASL compiler vendor ID */
u32 asl_compiler_revision; /* ASL compiler revision number */
+} acpi_header_t;
+/* A maximum number of 32 ACPI tables ought to be enough for now. */
Please remove the ending .
+#define MAX_ACPI_TABLES 32
+/* RSDT (Root System Description Table) */ +struct acpi_rsdt {
struct acpi_table_header header;
u32 entry[MAX_ACPI_TABLES];
+};
+/* XSDT (Extended System Description Table) */ +struct acpi_xsdt {
struct acpi_table_header header;
u64 entry[MAX_ACPI_TABLES];
+};
+/* MCFG (PCI Express MMIO config space BAR description table) */ +struct acpi_mcfg {
struct acpi_table_header header;
u8 reserved[8];
+};
+struct acpi_mcfg_mmconfig {
u32 base_address;
u32 base_reserved;
u16 pci_segment_group_number;
u8 start_bus_number;
u8 end_bus_number;
u8 reserved[4];
+};
+/* MADT (Multiple APIC Description Table) */ +struct acpi_madt {
struct acpi_table_header header;
u32 lapic_addr; /* Local APIC address */
u32 flags; /* Multiple APIC flags */
+} acpi_madt_t;
+enum dev_scope_type {
SCOPE_PCI_ENDPOINT = 1,
SCOPE_PCI_SUB = 2,
SCOPE_IOAPIC = 3,
SCOPE_MSI_HPET = 4
+};
+typedef struct dev_scope {
u8 type;
u8 length;
u8 reserved[2];
u8 enumeration;
u8 start_bus;
struct {
u8 dev;
u8 fn;
} path[0];
+} __packed dev_scope_t;
+/* MADT: APIC Structure Type*/ +enum acpi_apic_types {
LOCALAPIC = 0, /* Processor local APIC */
IOAPIC = 1, /* I/O APIC */
IRQSOURCEOVERRIDE = 2, /* Interrupt source override */
NMITYPE = 3, /* NMI source */
LOCALNMITYPE = 4, /* Local APIC NMI */
LAPICADDRESSOVERRIDE = 5, /* Local APIC address override */
IOSAPIC = 6, /* I/O SAPIC */
LOCALSAPIC = 7, /* Local SAPIC */
PLATFORMIRQSOURCES = 8, /* Platform interrupt sources */
LOCALX2SAPIC = 9, /* Processor local x2APIC */
LOCALX2APICNMI = 10, /* Local x2APIC NMI */
+};
+/* MADT: Processor Local APIC Structure */ +struct acpi_madt_lapic {
u8 type; /* Type (0) */
u8 length; /* Length in bytes (8) */
u8 processor_id; /* ACPI processor ID */
u8 apic_id; /* Local APIC ID */
u32 flags; /* Local APIC flags */
+};
+#define LOCAL_APIC_FLAG_ENABLED (1 << 0) +/* bits 1-31: reserved */ +#define PCAT_COMPAT (1 << 0) +/* bits 1-31: reserved */
+/* MADT: Local APIC NMI Structure */ +struct acpi_madt_lapic_nmi {
u8 type; /* Type (4) */
u8 length; /* Length in bytes (6) */
u8 processor_id; /* ACPI processor ID */
u16 flags; /* MPS INTI flags */
u8 lint; /* Local APIC LINT# */
+};
+/* MADT: I/O APIC Structure */ +struct acpi_madt_ioapic {
u8 type; /* Type (1) */
u8 length; /* Length in bytes (12) */
u8 ioapic_id; /* I/O APIC ID */
u8 reserved;
u32 ioapic_addr; /* I/O APIC address */
u32 gsi_base; /* Global system interrupt base */
+};
+/* MADT: Interrupt Source Override Structure */ +struct acpi_madt_irqoverride {
u8 type; /* Type (2) */
u8 length; /* Length in bytes (10) */
u8 bus; /* ISA (0) */
u8 source; /* Bus-relative int. source (IRQ) */
u32 gsirq; /* Global system interrupt */
u16 flags; /* MPS INTI flags */
+};
+/* FADT (Fixed ACPI Description Table) */ +struct __packed acpi_fadt {
struct acpi_table_header header;
u32 firmware_ctrl;
u32 dsdt;
u8 model;
u8 preferred_pm_profile;
u16 sci_int;
u32 smi_cmd;
u8 acpi_enable;
u8 acpi_disable;
u8 s4bios_req;
u8 pstate_cnt;
u32 pm1a_evt_blk;
u32 pm1b_evt_blk;
u32 pm1a_cnt_blk;
u32 pm1b_cnt_blk;
u32 pm2_cnt_blk;
u32 pm_tmr_blk;
u32 gpe0_blk;
u32 gpe1_blk;
u8 pm1_evt_len;
u8 pm1_cnt_len;
u8 pm2_cnt_len;
u8 pm_tmr_len;
u8 gpe0_blk_len;
u8 gpe1_blk_len;
u8 gpe1_base;
u8 cst_cnt;
u16 p_lvl2_lat;
u16 p_lvl3_lat;
u16 flush_size;
u16 flush_stride;
u8 duty_offset;
u8 duty_width;
u8 day_alrm;
u8 mon_alrm;
u8 century;
u16 iapc_boot_arch;
u8 res2;
u32 flags;
struct acpi_gen_regaddr reset_reg;
u8 reset_value;
u8 res3;
u8 res4;
u8 res5;
u32 x_firmware_ctl_l;
u32 x_firmware_ctl_h;
u32 x_dsdt_l;
u32 x_dsdt_h;
struct acpi_gen_regaddr x_pm1a_evt_blk;
struct acpi_gen_regaddr x_pm1b_evt_blk;
struct acpi_gen_regaddr x_pm1a_cnt_blk;
struct acpi_gen_regaddr x_pm1b_cnt_blk;
struct acpi_gen_regaddr x_pm2_cnt_blk;
struct acpi_gen_regaddr x_pm_tmr_blk;
struct acpi_gen_regaddr x_gpe0_blk;
struct acpi_gen_regaddr x_gpe1_blk;
+};
+/* Flags for p_lvl2_lat and p_lvl3_lat */ +#define ACPI_FADT_C2_NOT_SUPPORTED 101 +#define ACPI_FADT_C3_NOT_SUPPORTED 1001
+/* FADT Feature Flags */ +#define ACPI_FADT_WBINVD (1 << 0) +#define ACPI_FADT_WBINVD_FLUSH (1 << 1) +#define ACPI_FADT_C1_SUPPORTED (1 << 2) +#define ACPI_FADT_C2_MP_SUPPORTED (1 << 3) +#define ACPI_FADT_POWER_BUTTON (1 << 4) +#define ACPI_FADT_SLEEP_BUTTON (1 << 5) +#define ACPI_FADT_FIXED_RTC (1 << 6) +#define ACPI_FADT_S4_RTC_WAKE (1 << 7) +#define ACPI_FADT_32BIT_TIMER (1 << 8) +#define ACPI_FADT_DOCKING_SUPPORTED (1 << 9) +#define ACPI_FADT_RESET_REGISTER (1 << 10) +#define ACPI_FADT_SEALED_CASE (1 << 11) +#define ACPI_FADT_HEADLESS (1 << 12) +#define ACPI_FADT_SLEEP_TYPE (1 << 13) +#define ACPI_FADT_PCI_EXPRESS_WAKE (1 << 14) +#define ACPI_FADT_PLATFORM_CLOCK (1 << 15) +#define ACPI_FADT_S4_RTC_VALID (1 << 16) +#define ACPI_FADT_REMOTE_POWER_ON (1 << 17) +#define ACPI_FADT_APIC_CLUSTER (1 << 18) +#define ACPI_FADT_APIC_PHYSICAL (1 << 19) +/* Bits 20-31: reserved ACPI 3.0 & 4.0 */ +#define ACPI_FADT_HW_REDUCED_ACPI (1 << 20) +#define ACPI_FADT_LOW_PWR_IDLE_S0 (1 << 21) +/* bits 22-31: reserved ACPI 5.0 */
Nits: could we use tab to between macro names, value and comments?
+/* FADT Boot Architecture Flags */ +#define ACPI_FADT_LEGACY_DEVICES (1 << 0) +#define ACPI_FADT_8042 (1 << 1) +#define ACPI_FADT_VGA_NOT_PRESENT (1 << 2) +#define ACPI_FADT_MSI_NOT_SUPPORTED (1 << 3) +#define ACPI_FADT_NO_PCIE_ASPM_CONTROL (1 << 4) +#define ACPI_FADT_LEGACY_FREE 0x00 /* No legacy devices (including 8042) */
ditto.
+/* FADT Preferred Power Management Profile */ +#define PM_UNSPECIFIED 0 +#define PM_DESKTOP 1 +#define PM_MOBILE 2 +#define PM_WORKSTATION 3 +#define PM_ENTERPRISE_SERVER 4 +#define PM_SOHO_SERVER 5 +#define PM_APPLIANCE_PC 6 +#define PM_PERFORMANCE_SERVER 7 +#define PM_TABLET 8, /* ACPI 5.0 */
ditto.
+/* FACS (Firmware ACPI Control Structure) */ +struct acpi_facs {
char signature[4]; /* "FACS" */
u32 length; /* Length in bytes (>= 64) */
u32 hardware_signature; /* Hardware signature */
u32 firmware_waking_vector; /* Firmware waking vector */
u32 global_lock; /* Global lock */
u32 flags; /* FACS flags */
u32 x_firmware_waking_vector_l; /* X FW waking vector, low */
u32 x_firmware_waking_vector_h; /* X FW waking vector, high */
u8 version; /* ACPI 4.0: 2 */
u8 resv[31]; /* FIXME: 4.0: ospm_flags */
+};
+/* FACS flags */ +#define ACPI_FACS_S4BIOS_F (1 << 0) +#define ACPI_FACS_64BIT_WAKE_F (1 << 1) +/* Bits 31..2: reserved */
+/* These can be used by the target port. */
+unsigned long acpi_create_madt_lapics(unsigned long current); +int acpi_create_madt_ioapic(struct acpi_madt_ioapic *ioapic, u8 id, u32 addr,
Can we always use u32 for the parameters? like u32 id
u32 gsi_base);
+int acpi_create_madt_irqoverride(struct acpi_madt_irqoverride *irqoverride,
u8 bus, u8 source, u32 gsirq, u16 flags);
Ditto, for bus, source and flags
+unsigned long acpi_fill_madt(unsigned long current); +void acpi_create_fadt(struct acpi_fadt *fadt, struct acpi_facs *facs,
void *dsdt);
I believe checkpatch.pl will report indention warning here.
+int acpi_create_madt_lapic_nmi(struct acpi_madt_lapic_nmi *lapic_nmi, u8 cpu,
u16 flags, u8 lint);
Ditto, for cpu, flags and lint.
+unsigned long write_acpi_tables(unsigned long start);
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index dcfe9ee..6ecd6db 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -30,6 +30,7 @@ obj-y += physmem.o obj-$(CONFIG_X86_RAMTEST) += ramtest.o obj-y += sfi.o obj-y += string.o +obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o obj-y += tables.o obj-$(CONFIG_SYS_X86_TSC_TIMER) += tsc_timer.o obj-$(CONFIG_CMD_ZBOOT) += zimage.o diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c new file mode 100644 index 0000000..bd880ea --- /dev/null +++ b/arch/x86/lib/acpi_table.c @@ -0,0 +1,433 @@ +/*
- Based on acpi.c from coreboot
- Copyright (C) 2015, Saket Sinha saket.sinha89@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <cpu.h> +#include <dm.h> +#include <dm/uclass-internal.h> +#include <dm/lists.h> +#include <asm/acpi_table.h> +#include <asm/cpu.h> +#include <asm/ioapic.h> +#include <asm/lapic.h> +#include <asm/tables.h> +#include <asm/pci.h>
+extern const unsigned char AmlCode[];
Please add a comment block here to explain why we have to use CamelCase, in case someone later wants to improve but will fail.
+/** +* Add an ACPI table to the RSDT (and XSDT) structure, recalculate length +* and checksum. +*/ +static void acpi_add_table(struct acpi_rsdp *rsdp, void *table) +{
int i, entries_num;
struct acpi_rsdt *rsdt;
struct acpi_xsdt *xsdt = NULL;
/* The RSDT is mandatory while the XSDT is not */
rsdt = (struct acpi_rsdt *)rsdp->rsdt_address;
if (rsdp->xsdt_address)
xsdt = (struct acpi_xsdt *)((u32)rsdp->xsdt_address);
/* This should always be MAX_ACPI_TABLES */
entries_num = ARRAY_SIZE(rsdt->entry);
for (i = 0; i < entries_num; i++) {
if (rsdt->entry[i] == 0)
break;
}
if (i >= entries_num) {
debug("ACPI: Error: too many tables.\n");
return;
}
/* Add table to the RSDT */
rsdt->entry[i] = (u32)table;
/* Fix RSDT length or the kernel will assume invalid entries */
rsdt->header.length = sizeof(acpi_header_t) + (sizeof(u32) * (i + 1));
/* Re-calculate checksum. */
Nits: please remove the ending .
rsdt->header.checksum = 0;
rsdt->header.checksum = table_compute_checksum((u8 *)rsdt,
rsdt->header.length);
/*
* And now the same thing for the XSDT. We use the same index as for
* now we want the XSDT and RSDT to always be in sync in uboot
Should be U-Boot
*/
if (xsdt) {
/* Add table to the XSDT */
xsdt->entry[i] = (u64)(u32)table;
/* Fix XSDT length */
xsdt->header.length = sizeof(acpi_header_t) +
(sizeof(u64) * (i + 1));
Can we adjust the indention here, to align with sizeof above?
/* Re-calculate checksum */
xsdt->header.checksum = 0;
xsdt->header.checksum = table_compute_checksum((u8 *)xsdt,
xsdt->header.length);
}
+}
+static int acpi_create_madt_lapic(struct acpi_madt_lapic *lapic,
u8 cpu, u8 apic)
I believe chckpatch.pl will report indention warnings. Please fix this globally.
+{
lapic->type = LOCALAPIC; /* Local APIC structure */
lapic->length = sizeof(struct acpi_madt_lapic);
lapic->flags = LOCAL_APIC_FLAG_ENABLED; /* Processor/LAPIC enabled */
lapic->processor_id = cpu;
lapic->apic_id = apic;
return lapic->length;
+}
+unsigned long acpi_create_madt_lapics(unsigned long current) +{
struct udevice *dev;
for (uclass_find_first_device(UCLASS_CPU, &dev);
dev;
uclass_find_next_device(&dev)) {
struct cpu_platdata *plat = dev_get_parent_platdata(dev);
current += acpi_create_madt_lapic
((struct acpi_madt_lapic *)current,
plat->cpu_id, plat->cpu_id);
}
return current;
+}
+int acpi_create_madt_ioapic(struct acpi_madt_ioapic *ioapic, u8 id, u32 addr,
u32 gsi_base)
+{
ioapic->type = IOAPIC;
ioapic->length = sizeof(struct acpi_madt_ioapic);
ioapic->reserved = 0x00;
ioapic->gsi_base = gsi_base;
ioapic->ioapic_id = id;
ioapic->ioapic_addr = addr;
return ioapic->length;
+}
+int acpi_create_madt_irqoverride(struct acpi_madt_irqoverride *irqoverride,
u8 bus, u8 source, u32 gsirq, u16 flags)
+{
irqoverride->type = IRQSOURCEOVERRIDE;
irqoverride->length = sizeof(struct acpi_madt_irqoverride);
irqoverride->bus = bus;
irqoverride->source = source;
irqoverride->gsirq = gsirq;
irqoverride->flags = flags;
return irqoverride->length;
+}
+int acpi_create_madt_lapic_nmi(struct acpi_madt_lapic_nmi *lapic_nmi,
u8 cpu, u16 flags, u8 lint)
+{
lapic_nmi->type = LOCALNMITYPE;
lapic_nmi->length = sizeof(struct acpi_madt_lapic_nmi);
lapic_nmi->flags = flags;
lapic_nmi->processor_id = cpu;
lapic_nmi->lint = lint;
return lapic_nmi->length;
+}
+static void fill_header(acpi_header_t *header, char *signature, int length) +{
memcpy(header->signature, signature, length);
memcpy(header->oem_id, OEM_ID, 6);
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
memcpy(header->asl_compiler_id, ASLC, 4);
+}
+static void acpi_create_madt(struct acpi_madt *madt) +{
acpi_header_t *header = &(madt->header);
unsigned long current = (unsigned long)madt + sizeof(struct acpi_madt);
memset((void *)madt, 0, sizeof(struct acpi_madt));
/* Fill out header fields. */
Nits: please remove the ending .
fill_header(header, "APIC", 4);
header->length = sizeof(struct acpi_madt);
/* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */
header->revision = ACPI_REV_ACPI_2_0;
madt->lapic_addr = LAPIC_DEFAULT_BASE;
madt->flags = PCAT_COMPAT;
current = acpi_fill_madt(current);
/* (Re)calculate length and checksum */
header->length = current - (unsigned long)madt;
header->checksum = table_compute_checksum((void *)madt, header->length);
+}
+static int acpi_create_mcfg_mmconfig(struct acpi_mcfg_mmconfig *mmconfig,
u32 base, u16 seg_nr, u8 start, u8 end)
+{
memset(mmconfig, 0, sizeof(*mmconfig));
mmconfig->base_address = base;
mmconfig->base_reserved = 0;
mmconfig->pci_segment_group_number = seg_nr;
mmconfig->start_bus_number = start;
mmconfig->end_bus_number = end;
return sizeof(struct acpi_mcfg_mmconfig);
+}
+static unsigned long acpi_fill_mcfg(unsigned long current) +{
current += acpi_create_mcfg_mmconfig
((struct acpi_mcfg_mmconfig *)current,
Please remove the multiple spaces here.
CONFIG_PCIE_ECAM_BASE, 0x0, 0x0, 255);
return current;
+}
+/* MCFG is defined in the PCI Firmware Specification 3.0 */ +static void acpi_create_mcfg(struct acpi_mcfg *mcfg) +{
acpi_header_t *header = &(mcfg->header);
unsigned long current = (unsigned long)mcfg + sizeof(struct acpi_mcfg);
memset((void *)mcfg, 0, sizeof(struct acpi_mcfg));
/* Fill out header fields */
fill_header(header, "MCFG", 4);
header->length = sizeof(struct acpi_mcfg);
/* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */
header->revision = ACPI_REV_ACPI_2_0;
current = acpi_fill_mcfg(current);
/* (Re)calculate length and checksum */
header->length = current - (unsigned long)mcfg;
header->checksum = table_compute_checksum((void *)mcfg, header->length);
+}
+static void acpi_create_facs(struct acpi_facs *facs) +{
memset((void *)facs, 0, sizeof(struct acpi_facs));
memcpy(facs->signature, "FACS", 4);
facs->length = sizeof(struct acpi_facs);
facs->hardware_signature = 0;
facs->firmware_waking_vector = 0;
facs->global_lock = 0;
facs->flags = 0;
facs->x_firmware_waking_vector_l = 0;
facs->x_firmware_waking_vector_h = 0;
facs->version = 1; /* ACPI 1.0: 0, ACPI 2.0/3.0: 1, ACPI 4.0: 2 */
+}
+static void acpi_write_rsdt(struct acpi_rsdt *rsdt) +{
acpi_header_t *header = &(rsdt->header);
/* Fill out header fields */
fill_header(header, "RSDT", 4);
header->length = sizeof(struct acpi_rsdt);
/* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */
header->revision = ACPI_REV_ACPI_2_0;
/* Entries are filled in later, we come with an empty set */
/* Fix checksum */
header->checksum = table_compute_checksum((void *)rsdt,
sizeof(struct acpi_rsdt));
+}
+static void acpi_write_xsdt(struct acpi_xsdt *xsdt) +{
acpi_header_t *header = &(xsdt->header);
/* Fill out header fields */
fill_header(header, "XSDT", 4);
header->length = sizeof(struct acpi_xsdt);
/* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */
header->revision = ACPI_REV_ACPI_2_0;
/* Entries are filled in later, we come with an empty set */
/* Fix checksum */
header->checksum = table_compute_checksum((void *)xsdt,
sizeof(struct acpi_xsdt));
+}
+static void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt,
struct acpi_xsdt *xsdt)
+{
memset(rsdp, 0, sizeof(struct acpi_rsdp));
memcpy(rsdp->signature, RSDP_SIG, 8);
memcpy(rsdp->oem_id, OEM_ID, 6);
rsdp->length = sizeof(struct acpi_rsdp);
rsdp->rsdt_address = (u32)rsdt;
/*
* Revision: ACPI 1.0: 0, ACPI 2.0/3.0/4.0: 2
*
* Some OSes expect an XSDT to be present for RSD PTR revisions >= 2.
* If we don't have an ACPI XSDT, force ACPI 1.0 (and thus RSD PTR
* revision 0)
*/
if (xsdt == NULL) {
rsdp->revision = ACPI_RSDP_REV_ACPI_1_0;
} else {
rsdp->xsdt_address = (u64)(u32)xsdt;
rsdp->revision = ACPI_RSDP_REV_ACPI_2_0;
}
/* Calculate checksums */
rsdp->checksum = table_compute_checksum((void *)rsdp, 20);
rsdp->ext_checksum = table_compute_checksum((void *)rsdp,
sizeof(struct acpi_rsdp));
+}
+static void acpi_create_ssdt_generator(acpi_header_t *ssdt,
const char *oem_table_id)
+{
unsigned long current = (unsigned long)ssdt + sizeof(acpi_header_t);
memset((void *)ssdt, 0, sizeof(acpi_header_t));
memcpy(&ssdt->signature, "SSDT", 4);
/* Access size in ACPI 2.0c/3.0/4.0/5.0 */
ssdt->revision = ACPI_REV_ACPI_3_0;
memcpy(&ssdt->oem_id, OEM_ID, 6);
memcpy(&ssdt->oem_table_id, oem_table_id, 8);
ssdt->oem_revision = OEM_REVISION;
memcpy(&ssdt->asl_compiler_id, ASLC, 4);
ssdt->asl_compiler_revision = ASL_COMPILER_REVISION;
ssdt->length = sizeof(acpi_header_t);
/* (Re)calculate length and checksum */
ssdt->length = current - (unsigned long)ssdt;
ssdt->checksum = table_compute_checksum((void *)ssdt, ssdt->length);
+}
+unsigned long write_acpi_tables(unsigned long start) +{
unsigned long current;
struct acpi_rsdp *rsdp;
struct acpi_rsdt *rsdt;
struct acpi_xsdt *xsdt;
struct acpi_facs *facs;
acpi_header_t *dsdt;
struct acpi_fadt *fadt;
struct acpi_mcfg *mcfg;
struct acpi_madt *madt;
acpi_header_t *ssdt;
current = start;
/* Align ACPI tables to 16byte */
current = (ALIGN(current, 16));
Please remove the unnecessary outer () and fix this globally in this routine.
debug("ACPI: Writing ACPI tables at %lx.\n", start);
/* We need at least an RSDP and an RSDT Table */
rsdp = (struct acpi_rsdp *)current;
current += sizeof(struct acpi_rsdp);
current = (ALIGN(current, 16));
rsdt = (struct acpi_rsdt *)current;
current += sizeof(struct acpi_rsdt);
current = (ALIGN(current, 16));
xsdt = (struct acpi_xsdt *)current;
current += sizeof(struct acpi_xsdt);
current = (ALIGN(current, 16));
/* clear all table memory */
memset((void *)start, 0, current - start);
acpi_write_rsdp(rsdp, rsdt, xsdt);
acpi_write_rsdt(rsdt);
acpi_write_xsdt(xsdt);
debug("ACPI: * FACS\n");
facs = (struct acpi_facs *)current;
current += sizeof(struct acpi_facs);
current = (ALIGN(current, 16));
acpi_create_facs(facs);
debug("ACPI: * DSDT\n");
dsdt = (acpi_header_t *)current;
memcpy(dsdt, &AmlCode, sizeof(acpi_header_t));
if (dsdt->length >= sizeof(acpi_header_t)) {
current += sizeof(acpi_header_t);
memcpy((char *)current,
(char *)&AmlCode + sizeof(acpi_header_t),
dsdt->length - sizeof(acpi_header_t));
current += dsdt->length - sizeof(acpi_header_t);
/* (Re)calculate length and checksum */
dsdt->length = current - (unsigned long)dsdt;
dsdt->checksum = 0;
dsdt->checksum = table_compute_checksum((void *)dsdt,
dsdt->length);
}
current = (ALIGN(current, 16));
debug("ACPI: * FADT\n");
fadt = (struct acpi_fadt *)current;
current += sizeof(struct acpi_fadt);
current = (ALIGN(current, 16));
acpi_create_fadt(fadt, facs, dsdt);
acpi_add_table(rsdp, fadt);
debug("ACPI: * MCFG\n");
mcfg = (struct acpi_mcfg *)current;
acpi_create_mcfg(mcfg);
if (mcfg->header.length > sizeof(struct acpi_mcfg)) {
current += mcfg->header.length;
current = (ALIGN(current, 16));
acpi_add_table(rsdp, mcfg);
}
debug("ACPI: * MADT\n");
madt = (struct acpi_madt *)current;
acpi_create_madt(madt);
if (madt->header.length > sizeof(struct acpi_madt)) {
current += madt->header.length;
acpi_add_table(rsdp, madt);
}
current = (ALIGN(current, 16));
debug("ACPI: * SSDT\n");
ssdt = (acpi_header_t *)current;
acpi_create_ssdt_generator(ssdt, ACPI_TABLE_CREATOR);
if (ssdt->length > sizeof(acpi_header_t)) {
current += ssdt->length;
acpi_add_table(rsdp, ssdt);
current = (ALIGN(current, 16));
}
Nits: please remove one blank linke.
debug("current = %lx\n", current);
debug("ACPI: done.\n");
Nits: please add one blank line before return.
return current;
+}
diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c index 75ffbc1..f15b2e2 100644 --- a/arch/x86/lib/tables.c +++ b/arch/x86/lib/tables.c @@ -8,6 +8,7 @@ #include <asm/sfi.h> #include <asm/mpspec.h> #include <asm/tables.h> +#include <asm/acpi_table.h>
u8 table_compute_checksum(void *v, int len) { @@ -51,4 +52,8 @@ void write_tables(void) rom_table_end = write_mp_table(rom_table_end); rom_table_end = ALIGN(rom_table_end, 1024); #endif +#ifdef CONFIG_GENERATE_ACPI_TABLE
rom_table_end = write_acpi_tables(rom_table_end);
rom_table_end = ALIGN(rom_table_end, 1024);
+#endif } diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 1c949fc..ed30bf5 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -297,6 +297,17 @@ $(obj)/%.dtb: $(src)/%.dts FORCE
dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp)
+# ACPI +# --------------------------------------------------------------------------- +quiet_cmd_acpi_c_asl= ASL $@ +cmd_acpi_c_asl= \
$(CPP) -x assembler-with-cpp -P -o $<.tmp $<; \
iasl -p $< -tc -va $<.tmp; \
mv $(patsubst %.asl,%.hex,$<) $@
+$(obj)/%.c: $(src)/%.asl
$(call cmd,acpi_c_asl)
# Bzip2 # ---------------------------------------------------------------------------
--
Regards, Bin

Hi Bin,
Please find my response inline -
On Tue, Aug 18, 2015 at 12:36 PM, Bin Meng bmeng.cn@gmail.com wrote:
Hi Saket,
On Tue, Aug 18, 2015 at 3:29 AM, Saket Sinha saket.sinha89@gmail.com wrote:
Implement write_acpi_table() to create a minimal working ACPI table. This includes writing FACS, XSDT, RSDP, FADT, MCFG, MADT, DSDT & SSDT ACPI table entries.
Use a Kconfig option GENERATE_ACPI_TABLE to tell U-Boot whether we need actually write the APCI table just like we did for PIRQ routing, MP table and SFI tables. With ACPI table existence, linux kernel gets control of power management, thermal management, configuration management and monitoring in hardware.
Nice write-up!
Signed-off-by: Saket Sinha saket.sinha89@gmail.com
arch/x86/Kconfig | 9 + arch/x86/include/asm/acpi_table.h | 390 ++++++++++++++++++++++++++++++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/acpi_table.c | 433 ++++++++++++++++++++++++++++++++++++++ arch/x86/lib/tables.c | 5 + scripts/Makefile.lib | 11 + 6 files changed, 849 insertions(+) create mode 100644 arch/x86/include/asm/acpi_table.h create mode 100644 arch/x86/lib/acpi_table.c
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 01ed760..ae881a1 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -344,6 +344,15 @@ config GENERATE_MP_TABLE multiprocessing as well as symmetric I/O interrupt handling with the local APIC and I/O APIC.
+config GENERATE_ACPI_TABLE
bool "Generate an ACPI (Advanced Configuration and Power Interface) table"
default n
help
The Advanced Configuration and Power Interface (ACPI) specification
provides an open standard for device configuration and management
by the operating system. It defines platform-independent interfaces
for configuration and power management monitoring.
endmenu
config MAX_PIRQ_LINKS diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h new file mode 100644 index 0000000..a813a0a --- /dev/null +++ b/arch/x86/include/asm/acpi_table.h @@ -0,0 +1,390 @@ +/*
- Based on acpi.c from coreboot
- Copyright (C) 2015, Saket Sinha saket.sinha89@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <malloc.h> +#include <asm/post.h> +#include <linux/string.h>
+#define RSDP_SIG "RSD PTR " /* RSDT pointer signature */ +#define ACPI_TABLE_CREATOR "UBOOT " /* Must be exactly 8 bytes long! */ +#define OEM_ID "UBOOT " /* Must be exactly 6 bytes long! */ +#define ASLC "INTL" /* Must be exactly 4 bytes long! */
Nits: could we use tab to between macro names, value and comments?
Addressed in patchset series v6.
+#define OEM_REVISION 42 +#define ASL_COMPILER_REVISION 42
ditto
Addressed in patchset series v6.
+#define APM_CNT 0xb2 +#define APM_CNT_CST_CONTROL 0x85 +#define APM_CNT_PST_CONTROL 0x80 +#define APM_CNT_ACPI_DISABLE 0x1e +#define APM_CNT_ACPI_ENABLE 0xe1 +#define APM_CNT_MBI_UPDATE 0xeb +#define APM_CNT_GNVS_UPDATE 0xea +#define APM_CNT_FINALIZE 0xcb +#define APM_CNT_LEGACY 0xcc +#define APM_ST 0xb3
ditto, and can you add some comments on what these are?
Addressed in patchset series v6.
+#define MP_IRQ_POLARITY_DEFAULT 0x0 +#define MP_IRQ_POLARITY_HIGH 0x1 +#define MP_IRQ_POLARITY_LOW 0x3 +#define MP_IRQ_POLARITY_MASK 0x3 +#define MP_IRQ_TRIGGER_DEFAULT 0x0 +#define MP_IRQ_TRIGGER_EDGE 0x4 +#define MP_IRQ_TRIGGER_LEVEL 0xc +#define MP_IRQ_TRIGGER_MASK 0xc
ditto, and can you add some comments on what these are?
Addressed in patchset series v6.
+#define ACTL 0x00 +#define SCIS_MASK 0x07 +#define SCIS_IRQ9 0x00 +#define SCIS_IRQ10 0x01 +#define SCIS_IRQ11 0x02 +#define SCIS_IRQ20 0x04 +#define SCIS_IRQ21 0x05 +#define SCIS_IRQ22 0x06 +#define SCIS_IRQ23 0x07
ditto, and can you add some comments on what these are?
Addressed in patchset series v6.
+enum acpi_bus_type {
PIC = 0,
APIC = 2,
ETHIGH = 5
+};
I remember I pointed this out in previous version that the name of PIC, APIC is too generic.
Addressed in patchset series v6.
+#define ACPI_REV_ACPI_1_0 1 +#define ACPI_REV_ACPI_2_0 1 +#define ACPI_REV_ACPI_3_0 2 +#define ACPI_REV_ACPI_4_0 3 +#define ACPI_REV_ACPI_5_0 5
+#define ACPI_RSDP_REV_ACPI_1_0 0 +#define ACPI_RSDP_REV_ACPI_2_0 2
+typedef struct acpi_gen_regaddr {
u8 space_id; /* Address space ID */
u8 bit_width; /* Register size in bits */
u8 bit_offset; /* Register bit offset */
union {
/* Reserved in ACPI 2.0 - 2.0b */
u8 resv;
/* Access size in ACPI 2.0c/3.0/4.0/5.0 */
u8 access_size;
};
u32 addrl; /* Register address, low 32 bits */
u32 addrh; /* Register address, high 32 bits */
+} acpi_addr_t;
+/* RSDP (Root System Description Pointer) +Note: ACPI 1.0 didn't have length, xsdt_address, and ext_checksum. */
Please use multi-line comment format. Please fix this globally (I think I pointed this out in previous review)
Addressed in patchset series v6.
+struct acpi_rsdp {
char signature[8]; /* RSDP signature */
u8 checksum; /* Checksum of the first 20 bytes */
char oem_id[6]; /* OEM ID */
u8 revision; /* 0 for ACPI 1.0, 2 for ACPI 2.0/3.0/4.0 */
u32 rsdt_address; /* Physical address of RSDT (32 bits) */
u32 length; /* Total RSDP length (incl. extended part) */
u64 xsdt_address; /* Physical address of XSDT (64 bits) */
u8 ext_checksum; /* Checksum of the whole table */
u8 reserved[3];
+};
+enum acpi_address_space_type {
ACPI_ADDRESS_SPACE_MEMORY = 0, /* System memory */
ACPI_ADDRESS_SPACE_IO = 1, /* System I/O */
ACPI_ADDRESS_SPACE_PCI = 2, /* PCI config space */
ACPI_ADDRESS_SPACE_EC = 3, /* Embedded controller */
ACPI_ADDRESS_SPACE_SMBUS = 4, /* SMBus */
ACPI_ADDRESS_SPACE_PCC = 0x0a, /* Platform Comm. Channel */
ACPI_ADDRESS_SPACE_FIXED = 0x7f /* Functional fixed hardware */
+};
+#define ACPI_FFIXEDHW_VENDOR_INTEL 1 /* Intel */ +#define ACPI_FFIXEDHW_CLASS_HLT 0 /* C1 Halt */ +#define ACPI_FFIXEDHW_CLASS_IO_HLT 1 /* C1 I/O then Halt */ +#define ACPI_FFIXEDHW_CLASS_MWAIT 2 /* MWAIT Native C-state */ +#define ACPI_FFIXEDHW_FLAG_HW_COORD 1 /* Hardware Coordination bit */ +#define ACPI_FFIXEDHW_FLAG_BM_STS 2 /* BM_STS avoidance bit */
+/* Access size definitions for Generic address structure */ +enum acpi_address_space_size {
ACPI_ACCESS_SIZE_UNDEFINED = 0, /* Undefined (legacy reasons) */
ACPI_ACCESS_SIZE_BYTE_ACCESS = 1,
ACPI_ACCESS_SIZE_WORD_ACCESS = 2,
ACPI_ACCESS_SIZE_DWORD_ACCESS = 3,
ACPI_ACCESS_SIZE_QWORD_ACCESS = 4
+};
+/* Generic ACPI header, provided by (almost) all tables */ +typedef struct acpi_table_header {
char signature[4]; /* ACPI signature (4 ASCII characters) */
u32 length; /* Table length in bytes (incl. header) */
u8 revision; /* Table version (not ACPI version!) */
volatile u8 checksum; /* To make sum of entire table == 0 */
char oem_id[6]; /* OEM identification */
char oem_table_id[8]; /* OEM table identification */
u32 oem_revision; /* OEM revision number */
char asl_compiler_id[4]; /* ASL compiler vendor ID */
u32 asl_compiler_revision; /* ASL compiler revision number */
+} acpi_header_t;
+/* A maximum number of 32 ACPI tables ought to be enough for now. */
Please remove the ending .
Addressed in patchset series v6.
+#define MAX_ACPI_TABLES 32
+/* RSDT (Root System Description Table) */ +struct acpi_rsdt {
struct acpi_table_header header;
u32 entry[MAX_ACPI_TABLES];
+};
+/* XSDT (Extended System Description Table) */ +struct acpi_xsdt {
struct acpi_table_header header;
u64 entry[MAX_ACPI_TABLES];
+};
+/* MCFG (PCI Express MMIO config space BAR description table) */ +struct acpi_mcfg {
struct acpi_table_header header;
u8 reserved[8];
+};
+struct acpi_mcfg_mmconfig {
u32 base_address;
u32 base_reserved;
u16 pci_segment_group_number;
u8 start_bus_number;
u8 end_bus_number;
u8 reserved[4];
+};
+/* MADT (Multiple APIC Description Table) */ +struct acpi_madt {
struct acpi_table_header header;
u32 lapic_addr; /* Local APIC address */
u32 flags; /* Multiple APIC flags */
+} acpi_madt_t;
+enum dev_scope_type {
SCOPE_PCI_ENDPOINT = 1,
SCOPE_PCI_SUB = 2,
SCOPE_IOAPIC = 3,
SCOPE_MSI_HPET = 4
+};
+typedef struct dev_scope {
u8 type;
u8 length;
u8 reserved[2];
u8 enumeration;
u8 start_bus;
struct {
u8 dev;
u8 fn;
} path[0];
+} __packed dev_scope_t;
+/* MADT: APIC Structure Type*/ +enum acpi_apic_types {
LOCALAPIC = 0, /* Processor local APIC */
IOAPIC = 1, /* I/O APIC */
IRQSOURCEOVERRIDE = 2, /* Interrupt source override */
NMITYPE = 3, /* NMI source */
LOCALNMITYPE = 4, /* Local APIC NMI */
LAPICADDRESSOVERRIDE = 5, /* Local APIC address override */
IOSAPIC = 6, /* I/O SAPIC */
LOCALSAPIC = 7, /* Local SAPIC */
PLATFORMIRQSOURCES = 8, /* Platform interrupt sources */
LOCALX2SAPIC = 9, /* Processor local x2APIC */
LOCALX2APICNMI = 10, /* Local x2APIC NMI */
+};
+/* MADT: Processor Local APIC Structure */ +struct acpi_madt_lapic {
u8 type; /* Type (0) */
u8 length; /* Length in bytes (8) */
u8 processor_id; /* ACPI processor ID */
u8 apic_id; /* Local APIC ID */
u32 flags; /* Local APIC flags */
+};
+#define LOCAL_APIC_FLAG_ENABLED (1 << 0) +/* bits 1-31: reserved */ +#define PCAT_COMPAT (1 << 0) +/* bits 1-31: reserved */
+/* MADT: Local APIC NMI Structure */ +struct acpi_madt_lapic_nmi {
u8 type; /* Type (4) */
u8 length; /* Length in bytes (6) */
u8 processor_id; /* ACPI processor ID */
u16 flags; /* MPS INTI flags */
u8 lint; /* Local APIC LINT# */
+};
+/* MADT: I/O APIC Structure */ +struct acpi_madt_ioapic {
u8 type; /* Type (1) */
u8 length; /* Length in bytes (12) */
u8 ioapic_id; /* I/O APIC ID */
u8 reserved;
u32 ioapic_addr; /* I/O APIC address */
u32 gsi_base; /* Global system interrupt base */
+};
+/* MADT: Interrupt Source Override Structure */ +struct acpi_madt_irqoverride {
u8 type; /* Type (2) */
u8 length; /* Length in bytes (10) */
u8 bus; /* ISA (0) */
u8 source; /* Bus-relative int. source (IRQ) */
u32 gsirq; /* Global system interrupt */
u16 flags; /* MPS INTI flags */
+};
+/* FADT (Fixed ACPI Description Table) */ +struct __packed acpi_fadt {
struct acpi_table_header header;
u32 firmware_ctrl;
u32 dsdt;
u8 model;
u8 preferred_pm_profile;
u16 sci_int;
u32 smi_cmd;
u8 acpi_enable;
u8 acpi_disable;
u8 s4bios_req;
u8 pstate_cnt;
u32 pm1a_evt_blk;
u32 pm1b_evt_blk;
u32 pm1a_cnt_blk;
u32 pm1b_cnt_blk;
u32 pm2_cnt_blk;
u32 pm_tmr_blk;
u32 gpe0_blk;
u32 gpe1_blk;
u8 pm1_evt_len;
u8 pm1_cnt_len;
u8 pm2_cnt_len;
u8 pm_tmr_len;
u8 gpe0_blk_len;
u8 gpe1_blk_len;
u8 gpe1_base;
u8 cst_cnt;
u16 p_lvl2_lat;
u16 p_lvl3_lat;
u16 flush_size;
u16 flush_stride;
u8 duty_offset;
u8 duty_width;
u8 day_alrm;
u8 mon_alrm;
u8 century;
u16 iapc_boot_arch;
u8 res2;
u32 flags;
struct acpi_gen_regaddr reset_reg;
u8 reset_value;
u8 res3;
u8 res4;
u8 res5;
u32 x_firmware_ctl_l;
u32 x_firmware_ctl_h;
u32 x_dsdt_l;
u32 x_dsdt_h;
struct acpi_gen_regaddr x_pm1a_evt_blk;
struct acpi_gen_regaddr x_pm1b_evt_blk;
struct acpi_gen_regaddr x_pm1a_cnt_blk;
struct acpi_gen_regaddr x_pm1b_cnt_blk;
struct acpi_gen_regaddr x_pm2_cnt_blk;
struct acpi_gen_regaddr x_pm_tmr_blk;
struct acpi_gen_regaddr x_gpe0_blk;
struct acpi_gen_regaddr x_gpe1_blk;
+};
+/* Flags for p_lvl2_lat and p_lvl3_lat */ +#define ACPI_FADT_C2_NOT_SUPPORTED 101 +#define ACPI_FADT_C3_NOT_SUPPORTED 1001
+/* FADT Feature Flags */ +#define ACPI_FADT_WBINVD (1 << 0) +#define ACPI_FADT_WBINVD_FLUSH (1 << 1) +#define ACPI_FADT_C1_SUPPORTED (1 << 2) +#define ACPI_FADT_C2_MP_SUPPORTED (1 << 3) +#define ACPI_FADT_POWER_BUTTON (1 << 4) +#define ACPI_FADT_SLEEP_BUTTON (1 << 5) +#define ACPI_FADT_FIXED_RTC (1 << 6) +#define ACPI_FADT_S4_RTC_WAKE (1 << 7) +#define ACPI_FADT_32BIT_TIMER (1 << 8) +#define ACPI_FADT_DOCKING_SUPPORTED (1 << 9) +#define ACPI_FADT_RESET_REGISTER (1 << 10) +#define ACPI_FADT_SEALED_CASE (1 << 11) +#define ACPI_FADT_HEADLESS (1 << 12) +#define ACPI_FADT_SLEEP_TYPE (1 << 13) +#define ACPI_FADT_PCI_EXPRESS_WAKE (1 << 14) +#define ACPI_FADT_PLATFORM_CLOCK (1 << 15) +#define ACPI_FADT_S4_RTC_VALID (1 << 16) +#define ACPI_FADT_REMOTE_POWER_ON (1 << 17) +#define ACPI_FADT_APIC_CLUSTER (1 << 18) +#define ACPI_FADT_APIC_PHYSICAL (1 << 19) +/* Bits 20-31: reserved ACPI 3.0 & 4.0 */ +#define ACPI_FADT_HW_REDUCED_ACPI (1 << 20) +#define ACPI_FADT_LOW_PWR_IDLE_S0 (1 << 21) +/* bits 22-31: reserved ACPI 5.0 */
Nits: could we use tab to between macro names, value and comments?
Addressed in patchset series v6.
+/* FADT Boot Architecture Flags */ +#define ACPI_FADT_LEGACY_DEVICES (1 << 0) +#define ACPI_FADT_8042 (1 << 1) +#define ACPI_FADT_VGA_NOT_PRESENT (1 << 2) +#define ACPI_FADT_MSI_NOT_SUPPORTED (1 << 3) +#define ACPI_FADT_NO_PCIE_ASPM_CONTROL (1 << 4) +#define ACPI_FADT_LEGACY_FREE 0x00 /* No legacy devices (including 8042) */
ditto.
Addressed in patchset series v6.
+/* FADT Preferred Power Management Profile */ +#define PM_UNSPECIFIED 0 +#define PM_DESKTOP 1 +#define PM_MOBILE 2 +#define PM_WORKSTATION 3 +#define PM_ENTERPRISE_SERVER 4 +#define PM_SOHO_SERVER 5 +#define PM_APPLIANCE_PC 6 +#define PM_PERFORMANCE_SERVER 7 +#define PM_TABLET 8, /* ACPI 5.0 */
ditto.
Addressed in patchset series v6.
+/* FACS (Firmware ACPI Control Structure) */ +struct acpi_facs {
char signature[4]; /* "FACS" */
u32 length; /* Length in bytes (>= 64) */
u32 hardware_signature; /* Hardware signature */
u32 firmware_waking_vector; /* Firmware waking vector */
u32 global_lock; /* Global lock */
u32 flags; /* FACS flags */
u32 x_firmware_waking_vector_l; /* X FW waking vector, low */
u32 x_firmware_waking_vector_h; /* X FW waking vector, high */
u8 version; /* ACPI 4.0: 2 */
u8 resv[31]; /* FIXME: 4.0: ospm_flags */
+};
+/* FACS flags */ +#define ACPI_FACS_S4BIOS_F (1 << 0) +#define ACPI_FACS_64BIT_WAKE_F (1 << 1) +/* Bits 31..2: reserved */
+/* These can be used by the target port. */
+unsigned long acpi_create_madt_lapics(unsigned long current); +int acpi_create_madt_ioapic(struct acpi_madt_ioapic *ioapic, u8 id, u32 addr,
Can we always use u32 for the parameters? like u32 id
These will make me change all the structure and recheck that nothing breaks since these values are getting assigned to the table structures directly. I do not think this makes any sense to have 4 bytes for something that can be fitted in 1 byte.
u32 gsi_base);
+int acpi_create_madt_irqoverride(struct acpi_madt_irqoverride *irqoverride,
u8 bus, u8 source, u32 gsirq, u16 flags);
Ditto, for bus, source and flags
Addressed in patchset series v6.
+unsigned long acpi_fill_madt(unsigned long current); +void acpi_create_fadt(struct acpi_fadt *fadt, struct acpi_facs *facs,
void *dsdt);
I believe checkpatch.pl will report indention warning here.
Addressed in patchset series v6.
+int acpi_create_madt_lapic_nmi(struct acpi_madt_lapic_nmi *lapic_nmi, u8 cpu,
u16 flags, u8 lint);
Ditto, for cpu, flags and lint.
I do not think this makes any sense to have 4 bytes for something that can be fitted in 1 byte.
+unsigned long write_acpi_tables(unsigned long start);
diff --git a/arch/x86/lib/Makefile b/arch/x86/lib/Makefile index dcfe9ee..6ecd6db 100644 --- a/arch/x86/lib/Makefile +++ b/arch/x86/lib/Makefile @@ -30,6 +30,7 @@ obj-y += physmem.o obj-$(CONFIG_X86_RAMTEST) += ramtest.o obj-y += sfi.o obj-y += string.o +obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi_table.o obj-y += tables.o obj-$(CONFIG_SYS_X86_TSC_TIMER) += tsc_timer.o obj-$(CONFIG_CMD_ZBOOT) += zimage.o diff --git a/arch/x86/lib/acpi_table.c b/arch/x86/lib/acpi_table.c new file mode 100644 index 0000000..bd880ea --- /dev/null +++ b/arch/x86/lib/acpi_table.c @@ -0,0 +1,433 @@ +/*
- Based on acpi.c from coreboot
- Copyright (C) 2015, Saket Sinha saket.sinha89@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <cpu.h> +#include <dm.h> +#include <dm/uclass-internal.h> +#include <dm/lists.h> +#include <asm/acpi_table.h> +#include <asm/cpu.h> +#include <asm/ioapic.h> +#include <asm/lapic.h> +#include <asm/tables.h> +#include <asm/pci.h>
+extern const unsigned char AmlCode[];
Please add a comment block here to explain why we have to use CamelCase, in case someone later wants to improve but will fail.
Addressed in patchset series v6.
+/** +* Add an ACPI table to the RSDT (and XSDT) structure, recalculate length +* and checksum. +*/ +static void acpi_add_table(struct acpi_rsdp *rsdp, void *table) +{
int i, entries_num;
struct acpi_rsdt *rsdt;
struct acpi_xsdt *xsdt = NULL;
/* The RSDT is mandatory while the XSDT is not */
rsdt = (struct acpi_rsdt *)rsdp->rsdt_address;
if (rsdp->xsdt_address)
xsdt = (struct acpi_xsdt *)((u32)rsdp->xsdt_address);
/* This should always be MAX_ACPI_TABLES */
entries_num = ARRAY_SIZE(rsdt->entry);
for (i = 0; i < entries_num; i++) {
if (rsdt->entry[i] == 0)
break;
}
if (i >= entries_num) {
debug("ACPI: Error: too many tables.\n");
return;
}
/* Add table to the RSDT */
rsdt->entry[i] = (u32)table;
/* Fix RSDT length or the kernel will assume invalid entries */
rsdt->header.length = sizeof(acpi_header_t) + (sizeof(u32) * (i + 1));
/* Re-calculate checksum. */
Nits: please remove the ending .
Addressed in patchset series v6.
rsdt->header.checksum = 0;
rsdt->header.checksum = table_compute_checksum((u8 *)rsdt,
rsdt->header.length);
/*
* And now the same thing for the XSDT. We use the same index as for
* now we want the XSDT and RSDT to always be in sync in uboot
Should be U-Boot
Addressed in patchset series v6.
*/
if (xsdt) {
/* Add table to the XSDT */
xsdt->entry[i] = (u64)(u32)table;
/* Fix XSDT length */
xsdt->header.length = sizeof(acpi_header_t) +
(sizeof(u64) * (i + 1));
Can we adjust the indention here, to align with sizeof above?
Addressed in patchset series v6.
/* Re-calculate checksum */
xsdt->header.checksum = 0;
xsdt->header.checksum = table_compute_checksum((u8 *)xsdt,
xsdt->header.length);
}
+}
+static int acpi_create_madt_lapic(struct acpi_madt_lapic *lapic,
u8 cpu, u8 apic)
I believe chckpatch.pl will report indention warnings. Please fix this globally.
Addressed in patchset series v6.
+{
lapic->type = LOCALAPIC; /* Local APIC structure */
lapic->length = sizeof(struct acpi_madt_lapic);
lapic->flags = LOCAL_APIC_FLAG_ENABLED; /* Processor/LAPIC enabled */
lapic->processor_id = cpu;
lapic->apic_id = apic;
return lapic->length;
+}
+unsigned long acpi_create_madt_lapics(unsigned long current) +{
struct udevice *dev;
for (uclass_find_first_device(UCLASS_CPU, &dev);
dev;
uclass_find_next_device(&dev)) {
struct cpu_platdata *plat = dev_get_parent_platdata(dev);
current += acpi_create_madt_lapic
((struct acpi_madt_lapic *)current,
plat->cpu_id, plat->cpu_id);
}
return current;
+}
+int acpi_create_madt_ioapic(struct acpi_madt_ioapic *ioapic, u8 id, u32 addr,
u32 gsi_base)
+{
ioapic->type = IOAPIC;
ioapic->length = sizeof(struct acpi_madt_ioapic);
ioapic->reserved = 0x00;
ioapic->gsi_base = gsi_base;
ioapic->ioapic_id = id;
ioapic->ioapic_addr = addr;
return ioapic->length;
+}
+int acpi_create_madt_irqoverride(struct acpi_madt_irqoverride *irqoverride,
u8 bus, u8 source, u32 gsirq, u16 flags)
+{
irqoverride->type = IRQSOURCEOVERRIDE;
irqoverride->length = sizeof(struct acpi_madt_irqoverride);
irqoverride->bus = bus;
irqoverride->source = source;
irqoverride->gsirq = gsirq;
irqoverride->flags = flags;
return irqoverride->length;
+}
+int acpi_create_madt_lapic_nmi(struct acpi_madt_lapic_nmi *lapic_nmi,
u8 cpu, u16 flags, u8 lint)
+{
lapic_nmi->type = LOCALNMITYPE;
lapic_nmi->length = sizeof(struct acpi_madt_lapic_nmi);
lapic_nmi->flags = flags;
lapic_nmi->processor_id = cpu;
lapic_nmi->lint = lint;
return lapic_nmi->length;
+}
+static void fill_header(acpi_header_t *header, char *signature, int length) +{
memcpy(header->signature, signature, length);
memcpy(header->oem_id, OEM_ID, 6);
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
memcpy(header->asl_compiler_id, ASLC, 4);
+}
+static void acpi_create_madt(struct acpi_madt *madt) +{
acpi_header_t *header = &(madt->header);
unsigned long current = (unsigned long)madt + sizeof(struct acpi_madt);
memset((void *)madt, 0, sizeof(struct acpi_madt));
/* Fill out header fields. */
Nits: please remove the ending .
Addressed in patchset series v6.
fill_header(header, "APIC", 4);
header->length = sizeof(struct acpi_madt);
/* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */
header->revision = ACPI_REV_ACPI_2_0;
madt->lapic_addr = LAPIC_DEFAULT_BASE;
madt->flags = PCAT_COMPAT;
current = acpi_fill_madt(current);
/* (Re)calculate length and checksum */
header->length = current - (unsigned long)madt;
header->checksum = table_compute_checksum((void *)madt, header->length);
+}
+static int acpi_create_mcfg_mmconfig(struct acpi_mcfg_mmconfig *mmconfig,
u32 base, u16 seg_nr, u8 start, u8 end)
+{
memset(mmconfig, 0, sizeof(*mmconfig));
mmconfig->base_address = base;
mmconfig->base_reserved = 0;
mmconfig->pci_segment_group_number = seg_nr;
mmconfig->start_bus_number = start;
mmconfig->end_bus_number = end;
return sizeof(struct acpi_mcfg_mmconfig);
+}
+static unsigned long acpi_fill_mcfg(unsigned long current) +{
current += acpi_create_mcfg_mmconfig
((struct acpi_mcfg_mmconfig *)current,
Please remove the multiple spaces here.
Addressed in patchset series v6.
CONFIG_PCIE_ECAM_BASE, 0x0, 0x0, 255);
return current;
+}
+/* MCFG is defined in the PCI Firmware Specification 3.0 */ +static void acpi_create_mcfg(struct acpi_mcfg *mcfg) +{
acpi_header_t *header = &(mcfg->header);
unsigned long current = (unsigned long)mcfg + sizeof(struct acpi_mcfg);
memset((void *)mcfg, 0, sizeof(struct acpi_mcfg));
/* Fill out header fields */
fill_header(header, "MCFG", 4);
header->length = sizeof(struct acpi_mcfg);
/* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */
header->revision = ACPI_REV_ACPI_2_0;
current = acpi_fill_mcfg(current);
/* (Re)calculate length and checksum */
header->length = current - (unsigned long)mcfg;
header->checksum = table_compute_checksum((void *)mcfg, header->length);
+}
+static void acpi_create_facs(struct acpi_facs *facs) +{
memset((void *)facs, 0, sizeof(struct acpi_facs));
memcpy(facs->signature, "FACS", 4);
facs->length = sizeof(struct acpi_facs);
facs->hardware_signature = 0;
facs->firmware_waking_vector = 0;
facs->global_lock = 0;
facs->flags = 0;
facs->x_firmware_waking_vector_l = 0;
facs->x_firmware_waking_vector_h = 0;
facs->version = 1; /* ACPI 1.0: 0, ACPI 2.0/3.0: 1, ACPI 4.0: 2 */
+}
+static void acpi_write_rsdt(struct acpi_rsdt *rsdt) +{
acpi_header_t *header = &(rsdt->header);
/* Fill out header fields */
fill_header(header, "RSDT", 4);
header->length = sizeof(struct acpi_rsdt);
/* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */
header->revision = ACPI_REV_ACPI_2_0;
/* Entries are filled in later, we come with an empty set */
/* Fix checksum */
header->checksum = table_compute_checksum((void *)rsdt,
sizeof(struct acpi_rsdt));
+}
+static void acpi_write_xsdt(struct acpi_xsdt *xsdt) +{
acpi_header_t *header = &(xsdt->header);
/* Fill out header fields */
fill_header(header, "XSDT", 4);
header->length = sizeof(struct acpi_xsdt);
/* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */
header->revision = ACPI_REV_ACPI_2_0;
/* Entries are filled in later, we come with an empty set */
/* Fix checksum */
header->checksum = table_compute_checksum((void *)xsdt,
sizeof(struct acpi_xsdt));
+}
+static void acpi_write_rsdp(struct acpi_rsdp *rsdp, struct acpi_rsdt *rsdt,
struct acpi_xsdt *xsdt)
+{
memset(rsdp, 0, sizeof(struct acpi_rsdp));
memcpy(rsdp->signature, RSDP_SIG, 8);
memcpy(rsdp->oem_id, OEM_ID, 6);
rsdp->length = sizeof(struct acpi_rsdp);
rsdp->rsdt_address = (u32)rsdt;
/*
* Revision: ACPI 1.0: 0, ACPI 2.0/3.0/4.0: 2
*
* Some OSes expect an XSDT to be present for RSD PTR revisions >= 2.
* If we don't have an ACPI XSDT, force ACPI 1.0 (and thus RSD PTR
* revision 0)
*/
if (xsdt == NULL) {
rsdp->revision = ACPI_RSDP_REV_ACPI_1_0;
} else {
rsdp->xsdt_address = (u64)(u32)xsdt;
rsdp->revision = ACPI_RSDP_REV_ACPI_2_0;
}
/* Calculate checksums */
rsdp->checksum = table_compute_checksum((void *)rsdp, 20);
rsdp->ext_checksum = table_compute_checksum((void *)rsdp,
sizeof(struct acpi_rsdp));
+}
+static void acpi_create_ssdt_generator(acpi_header_t *ssdt,
const char *oem_table_id)
+{
unsigned long current = (unsigned long)ssdt + sizeof(acpi_header_t);
memset((void *)ssdt, 0, sizeof(acpi_header_t));
memcpy(&ssdt->signature, "SSDT", 4);
/* Access size in ACPI 2.0c/3.0/4.0/5.0 */
ssdt->revision = ACPI_REV_ACPI_3_0;
memcpy(&ssdt->oem_id, OEM_ID, 6);
memcpy(&ssdt->oem_table_id, oem_table_id, 8);
ssdt->oem_revision = OEM_REVISION;
memcpy(&ssdt->asl_compiler_id, ASLC, 4);
ssdt->asl_compiler_revision = ASL_COMPILER_REVISION;
ssdt->length = sizeof(acpi_header_t);
/* (Re)calculate length and checksum */
ssdt->length = current - (unsigned long)ssdt;
ssdt->checksum = table_compute_checksum((void *)ssdt, ssdt->length);
+}
+unsigned long write_acpi_tables(unsigned long start) +{
unsigned long current;
struct acpi_rsdp *rsdp;
struct acpi_rsdt *rsdt;
struct acpi_xsdt *xsdt;
struct acpi_facs *facs;
acpi_header_t *dsdt;
struct acpi_fadt *fadt;
struct acpi_mcfg *mcfg;
struct acpi_madt *madt;
acpi_header_t *ssdt;
current = start;
/* Align ACPI tables to 16byte */
current = (ALIGN(current, 16));
Please remove the unnecessary outer () and fix this globally in this routine.
Addressed in patchset series v6.
debug("ACPI: Writing ACPI tables at %lx.\n", start);
/* We need at least an RSDP and an RSDT Table */
rsdp = (struct acpi_rsdp *)current;
current += sizeof(struct acpi_rsdp);
current = (ALIGN(current, 16));
rsdt = (struct acpi_rsdt *)current;
current += sizeof(struct acpi_rsdt);
current = (ALIGN(current, 16));
xsdt = (struct acpi_xsdt *)current;
current += sizeof(struct acpi_xsdt);
current = (ALIGN(current, 16));
/* clear all table memory */
memset((void *)start, 0, current - start);
acpi_write_rsdp(rsdp, rsdt, xsdt);
acpi_write_rsdt(rsdt);
acpi_write_xsdt(xsdt);
debug("ACPI: * FACS\n");
facs = (struct acpi_facs *)current;
current += sizeof(struct acpi_facs);
current = (ALIGN(current, 16));
acpi_create_facs(facs);
debug("ACPI: * DSDT\n");
dsdt = (acpi_header_t *)current;
memcpy(dsdt, &AmlCode, sizeof(acpi_header_t));
if (dsdt->length >= sizeof(acpi_header_t)) {
current += sizeof(acpi_header_t);
memcpy((char *)current,
(char *)&AmlCode + sizeof(acpi_header_t),
dsdt->length - sizeof(acpi_header_t));
current += dsdt->length - sizeof(acpi_header_t);
/* (Re)calculate length and checksum */
dsdt->length = current - (unsigned long)dsdt;
dsdt->checksum = 0;
dsdt->checksum = table_compute_checksum((void *)dsdt,
dsdt->length);
}
current = (ALIGN(current, 16));
debug("ACPI: * FADT\n");
fadt = (struct acpi_fadt *)current;
current += sizeof(struct acpi_fadt);
current = (ALIGN(current, 16));
acpi_create_fadt(fadt, facs, dsdt);
acpi_add_table(rsdp, fadt);
debug("ACPI: * MCFG\n");
mcfg = (struct acpi_mcfg *)current;
acpi_create_mcfg(mcfg);
if (mcfg->header.length > sizeof(struct acpi_mcfg)) {
current += mcfg->header.length;
current = (ALIGN(current, 16));
acpi_add_table(rsdp, mcfg);
}
debug("ACPI: * MADT\n");
madt = (struct acpi_madt *)current;
acpi_create_madt(madt);
if (madt->header.length > sizeof(struct acpi_madt)) {
current += madt->header.length;
acpi_add_table(rsdp, madt);
}
current = (ALIGN(current, 16));
debug("ACPI: * SSDT\n");
ssdt = (acpi_header_t *)current;
acpi_create_ssdt_generator(ssdt, ACPI_TABLE_CREATOR);
if (ssdt->length > sizeof(acpi_header_t)) {
current += ssdt->length;
acpi_add_table(rsdp, ssdt);
current = (ALIGN(current, 16));
}
Nits: please remove one blank linke.
Addressed in patchset series v6.
debug("current = %lx\n", current);
debug("ACPI: done.\n");
Nits: please add one blank line before return.
Addressed in patchset series v6.
return current;
+}
diff --git a/arch/x86/lib/tables.c b/arch/x86/lib/tables.c index 75ffbc1..f15b2e2 100644 --- a/arch/x86/lib/tables.c +++ b/arch/x86/lib/tables.c @@ -8,6 +8,7 @@ #include <asm/sfi.h> #include <asm/mpspec.h> #include <asm/tables.h> +#include <asm/acpi_table.h>
u8 table_compute_checksum(void *v, int len) { @@ -51,4 +52,8 @@ void write_tables(void) rom_table_end = write_mp_table(rom_table_end); rom_table_end = ALIGN(rom_table_end, 1024); #endif +#ifdef CONFIG_GENERATE_ACPI_TABLE
rom_table_end = write_acpi_tables(rom_table_end);
rom_table_end = ALIGN(rom_table_end, 1024);
+#endif } diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 1c949fc..ed30bf5 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -297,6 +297,17 @@ $(obj)/%.dtb: $(src)/%.dts FORCE
dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp)
+# ACPI +# --------------------------------------------------------------------------- +quiet_cmd_acpi_c_asl= ASL $@ +cmd_acpi_c_asl= \
$(CPP) -x assembler-with-cpp -P -o $<.tmp $<; \
iasl -p $< -tc -va $<.tmp; \
mv $(patsubst %.asl,%.hex,$<) $@
+$(obj)/%.c: $(src)/%.asl
$(call cmd,acpi_c_asl)
# Bzip2 # ---------------------------------------------------------------------------
--
Regards, Bin
Regards, Saket Sinha

Hi Saket,
On Fri, Aug 21, 2015 at 12:33 PM, Saket Sinha saket.sinha89@gmail.com wrote:
Hi Bin,
Please find my response inline -
On Tue, Aug 18, 2015 at 12:36 PM, Bin Meng bmeng.cn@gmail.com wrote:
Hi Saket,
On Tue, Aug 18, 2015 at 3:29 AM, Saket Sinha saket.sinha89@gmail.com wrote:
Implement write_acpi_table() to create a minimal working ACPI table. This includes writing FACS, XSDT, RSDP, FADT, MCFG, MADT, DSDT & SSDT ACPI table entries.
Use a Kconfig option GENERATE_ACPI_TABLE to tell U-Boot whether we need actually write the APCI table just like we did for PIRQ routing, MP table and SFI tables. With ACPI table existence, linux kernel gets control of power management, thermal management, configuration management and monitoring in hardware.
Nice write-up!
Signed-off-by: Saket Sinha saket.sinha89@gmail.com
arch/x86/Kconfig | 9 + arch/x86/include/asm/acpi_table.h | 390 ++++++++++++++++++++++++++++++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/acpi_table.c | 433 ++++++++++++++++++++++++++++++++++++++ arch/x86/lib/tables.c | 5 + scripts/Makefile.lib | 11 + 6 files changed, 849 insertions(+) create mode 100644 arch/x86/include/asm/acpi_table.h create mode 100644 arch/x86/lib/acpi_table.c
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 01ed760..ae881a1 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -344,6 +344,15 @@ config GENERATE_MP_TABLE multiprocessing as well as symmetric I/O interrupt handling with the local APIC and I/O APIC.
+config GENERATE_ACPI_TABLE
bool "Generate an ACPI (Advanced Configuration and Power Interface) table"
default n
help
The Advanced Configuration and Power Interface (ACPI) specification
provides an open standard for device configuration and management
by the operating system. It defines platform-independent interfaces
for configuration and power management monitoring.
endmenu
config MAX_PIRQ_LINKS diff --git a/arch/x86/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h new file mode 100644 index 0000000..a813a0a --- /dev/null +++ b/arch/x86/include/asm/acpi_table.h @@ -0,0 +1,390 @@ +/*
- Based on acpi.c from coreboot
- Copyright (C) 2015, Saket Sinha saket.sinha89@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <malloc.h> +#include <asm/post.h> +#include <linux/string.h>
+#define RSDP_SIG "RSD PTR " /* RSDT pointer signature */ +#define ACPI_TABLE_CREATOR "UBOOT " /* Must be exactly 8 bytes long! */ +#define OEM_ID "UBOOT " /* Must be exactly 6 bytes long! */ +#define ASLC "INTL" /* Must be exactly 4 bytes long! */
Nits: could we use tab to between macro names, value and comments?
Addressed in patchset series v6.
+#define OEM_REVISION 42 +#define ASL_COMPILER_REVISION 42
ditto
Addressed in patchset series v6.
+#define APM_CNT 0xb2 +#define APM_CNT_CST_CONTROL 0x85 +#define APM_CNT_PST_CONTROL 0x80 +#define APM_CNT_ACPI_DISABLE 0x1e +#define APM_CNT_ACPI_ENABLE 0xe1 +#define APM_CNT_MBI_UPDATE 0xeb +#define APM_CNT_GNVS_UPDATE 0xea +#define APM_CNT_FINALIZE 0xcb +#define APM_CNT_LEGACY 0xcc +#define APM_ST 0xb3
ditto, and can you add some comments on what these are?
Addressed in patchset series v6.
+#define MP_IRQ_POLARITY_DEFAULT 0x0 +#define MP_IRQ_POLARITY_HIGH 0x1 +#define MP_IRQ_POLARITY_LOW 0x3 +#define MP_IRQ_POLARITY_MASK 0x3 +#define MP_IRQ_TRIGGER_DEFAULT 0x0 +#define MP_IRQ_TRIGGER_EDGE 0x4 +#define MP_IRQ_TRIGGER_LEVEL 0xc +#define MP_IRQ_TRIGGER_MASK 0xc
ditto, and can you add some comments on what these are?
Addressed in patchset series v6.
+#define ACTL 0x00 +#define SCIS_MASK 0x07 +#define SCIS_IRQ9 0x00 +#define SCIS_IRQ10 0x01 +#define SCIS_IRQ11 0x02 +#define SCIS_IRQ20 0x04 +#define SCIS_IRQ21 0x05 +#define SCIS_IRQ22 0x06 +#define SCIS_IRQ23 0x07
ditto, and can you add some comments on what these are?
Addressed in patchset series v6.
+enum acpi_bus_type {
PIC = 0,
APIC = 2,
ETHIGH = 5
+};
I remember I pointed this out in previous version that the name of PIC, APIC is too generic.
Addressed in patchset series v6.
+#define ACPI_REV_ACPI_1_0 1 +#define ACPI_REV_ACPI_2_0 1 +#define ACPI_REV_ACPI_3_0 2 +#define ACPI_REV_ACPI_4_0 3 +#define ACPI_REV_ACPI_5_0 5
+#define ACPI_RSDP_REV_ACPI_1_0 0 +#define ACPI_RSDP_REV_ACPI_2_0 2
+typedef struct acpi_gen_regaddr {
u8 space_id; /* Address space ID */
u8 bit_width; /* Register size in bits */
u8 bit_offset; /* Register bit offset */
union {
/* Reserved in ACPI 2.0 - 2.0b */
u8 resv;
/* Access size in ACPI 2.0c/3.0/4.0/5.0 */
u8 access_size;
};
u32 addrl; /* Register address, low 32 bits */
u32 addrh; /* Register address, high 32 bits */
+} acpi_addr_t;
+/* RSDP (Root System Description Pointer) +Note: ACPI 1.0 didn't have length, xsdt_address, and ext_checksum. */
Please use multi-line comment format. Please fix this globally (I think I pointed this out in previous review)
Addressed in patchset series v6.
+struct acpi_rsdp {
char signature[8]; /* RSDP signature */
u8 checksum; /* Checksum of the first 20 bytes */
char oem_id[6]; /* OEM ID */
u8 revision; /* 0 for ACPI 1.0, 2 for ACPI 2.0/3.0/4.0 */
u32 rsdt_address; /* Physical address of RSDT (32 bits) */
u32 length; /* Total RSDP length (incl. extended part) */
u64 xsdt_address; /* Physical address of XSDT (64 bits) */
u8 ext_checksum; /* Checksum of the whole table */
u8 reserved[3];
+};
+enum acpi_address_space_type {
ACPI_ADDRESS_SPACE_MEMORY = 0, /* System memory */
ACPI_ADDRESS_SPACE_IO = 1, /* System I/O */
ACPI_ADDRESS_SPACE_PCI = 2, /* PCI config space */
ACPI_ADDRESS_SPACE_EC = 3, /* Embedded controller */
ACPI_ADDRESS_SPACE_SMBUS = 4, /* SMBus */
ACPI_ADDRESS_SPACE_PCC = 0x0a, /* Platform Comm. Channel */
ACPI_ADDRESS_SPACE_FIXED = 0x7f /* Functional fixed hardware */
+};
+#define ACPI_FFIXEDHW_VENDOR_INTEL 1 /* Intel */ +#define ACPI_FFIXEDHW_CLASS_HLT 0 /* C1 Halt */ +#define ACPI_FFIXEDHW_CLASS_IO_HLT 1 /* C1 I/O then Halt */ +#define ACPI_FFIXEDHW_CLASS_MWAIT 2 /* MWAIT Native C-state */ +#define ACPI_FFIXEDHW_FLAG_HW_COORD 1 /* Hardware Coordination bit */ +#define ACPI_FFIXEDHW_FLAG_BM_STS 2 /* BM_STS avoidance bit */
+/* Access size definitions for Generic address structure */ +enum acpi_address_space_size {
ACPI_ACCESS_SIZE_UNDEFINED = 0, /* Undefined (legacy reasons) */
ACPI_ACCESS_SIZE_BYTE_ACCESS = 1,
ACPI_ACCESS_SIZE_WORD_ACCESS = 2,
ACPI_ACCESS_SIZE_DWORD_ACCESS = 3,
ACPI_ACCESS_SIZE_QWORD_ACCESS = 4
+};
+/* Generic ACPI header, provided by (almost) all tables */ +typedef struct acpi_table_header {
char signature[4]; /* ACPI signature (4 ASCII characters) */
u32 length; /* Table length in bytes (incl. header) */
u8 revision; /* Table version (not ACPI version!) */
volatile u8 checksum; /* To make sum of entire table == 0 */
char oem_id[6]; /* OEM identification */
char oem_table_id[8]; /* OEM table identification */
u32 oem_revision; /* OEM revision number */
char asl_compiler_id[4]; /* ASL compiler vendor ID */
u32 asl_compiler_revision; /* ASL compiler revision number */
+} acpi_header_t;
+/* A maximum number of 32 ACPI tables ought to be enough for now. */
Please remove the ending .
Addressed in patchset series v6.
+#define MAX_ACPI_TABLES 32
+/* RSDT (Root System Description Table) */ +struct acpi_rsdt {
struct acpi_table_header header;
u32 entry[MAX_ACPI_TABLES];
+};
+/* XSDT (Extended System Description Table) */ +struct acpi_xsdt {
struct acpi_table_header header;
u64 entry[MAX_ACPI_TABLES];
+};
+/* MCFG (PCI Express MMIO config space BAR description table) */ +struct acpi_mcfg {
struct acpi_table_header header;
u8 reserved[8];
+};
+struct acpi_mcfg_mmconfig {
u32 base_address;
u32 base_reserved;
u16 pci_segment_group_number;
u8 start_bus_number;
u8 end_bus_number;
u8 reserved[4];
+};
+/* MADT (Multiple APIC Description Table) */ +struct acpi_madt {
struct acpi_table_header header;
u32 lapic_addr; /* Local APIC address */
u32 flags; /* Multiple APIC flags */
+} acpi_madt_t;
+enum dev_scope_type {
SCOPE_PCI_ENDPOINT = 1,
SCOPE_PCI_SUB = 2,
SCOPE_IOAPIC = 3,
SCOPE_MSI_HPET = 4
+};
+typedef struct dev_scope {
u8 type;
u8 length;
u8 reserved[2];
u8 enumeration;
u8 start_bus;
struct {
u8 dev;
u8 fn;
} path[0];
+} __packed dev_scope_t;
+/* MADT: APIC Structure Type*/ +enum acpi_apic_types {
LOCALAPIC = 0, /* Processor local APIC */
IOAPIC = 1, /* I/O APIC */
IRQSOURCEOVERRIDE = 2, /* Interrupt source override */
NMITYPE = 3, /* NMI source */
LOCALNMITYPE = 4, /* Local APIC NMI */
LAPICADDRESSOVERRIDE = 5, /* Local APIC address override */
IOSAPIC = 6, /* I/O SAPIC */
LOCALSAPIC = 7, /* Local SAPIC */
PLATFORMIRQSOURCES = 8, /* Platform interrupt sources */
LOCALX2SAPIC = 9, /* Processor local x2APIC */
LOCALX2APICNMI = 10, /* Local x2APIC NMI */
+};
+/* MADT: Processor Local APIC Structure */ +struct acpi_madt_lapic {
u8 type; /* Type (0) */
u8 length; /* Length in bytes (8) */
u8 processor_id; /* ACPI processor ID */
u8 apic_id; /* Local APIC ID */
u32 flags; /* Local APIC flags */
+};
+#define LOCAL_APIC_FLAG_ENABLED (1 << 0) +/* bits 1-31: reserved */ +#define PCAT_COMPAT (1 << 0) +/* bits 1-31: reserved */
+/* MADT: Local APIC NMI Structure */ +struct acpi_madt_lapic_nmi {
u8 type; /* Type (4) */
u8 length; /* Length in bytes (6) */
u8 processor_id; /* ACPI processor ID */
u16 flags; /* MPS INTI flags */
u8 lint; /* Local APIC LINT# */
+};
+/* MADT: I/O APIC Structure */ +struct acpi_madt_ioapic {
u8 type; /* Type (1) */
u8 length; /* Length in bytes (12) */
u8 ioapic_id; /* I/O APIC ID */
u8 reserved;
u32 ioapic_addr; /* I/O APIC address */
u32 gsi_base; /* Global system interrupt base */
+};
+/* MADT: Interrupt Source Override Structure */ +struct acpi_madt_irqoverride {
u8 type; /* Type (2) */
u8 length; /* Length in bytes (10) */
u8 bus; /* ISA (0) */
u8 source; /* Bus-relative int. source (IRQ) */
u32 gsirq; /* Global system interrupt */
u16 flags; /* MPS INTI flags */
+};
+/* FADT (Fixed ACPI Description Table) */ +struct __packed acpi_fadt {
struct acpi_table_header header;
u32 firmware_ctrl;
u32 dsdt;
u8 model;
u8 preferred_pm_profile;
u16 sci_int;
u32 smi_cmd;
u8 acpi_enable;
u8 acpi_disable;
u8 s4bios_req;
u8 pstate_cnt;
u32 pm1a_evt_blk;
u32 pm1b_evt_blk;
u32 pm1a_cnt_blk;
u32 pm1b_cnt_blk;
u32 pm2_cnt_blk;
u32 pm_tmr_blk;
u32 gpe0_blk;
u32 gpe1_blk;
u8 pm1_evt_len;
u8 pm1_cnt_len;
u8 pm2_cnt_len;
u8 pm_tmr_len;
u8 gpe0_blk_len;
u8 gpe1_blk_len;
u8 gpe1_base;
u8 cst_cnt;
u16 p_lvl2_lat;
u16 p_lvl3_lat;
u16 flush_size;
u16 flush_stride;
u8 duty_offset;
u8 duty_width;
u8 day_alrm;
u8 mon_alrm;
u8 century;
u16 iapc_boot_arch;
u8 res2;
u32 flags;
struct acpi_gen_regaddr reset_reg;
u8 reset_value;
u8 res3;
u8 res4;
u8 res5;
u32 x_firmware_ctl_l;
u32 x_firmware_ctl_h;
u32 x_dsdt_l;
u32 x_dsdt_h;
struct acpi_gen_regaddr x_pm1a_evt_blk;
struct acpi_gen_regaddr x_pm1b_evt_blk;
struct acpi_gen_regaddr x_pm1a_cnt_blk;
struct acpi_gen_regaddr x_pm1b_cnt_blk;
struct acpi_gen_regaddr x_pm2_cnt_blk;
struct acpi_gen_regaddr x_pm_tmr_blk;
struct acpi_gen_regaddr x_gpe0_blk;
struct acpi_gen_regaddr x_gpe1_blk;
+};
+/* Flags for p_lvl2_lat and p_lvl3_lat */ +#define ACPI_FADT_C2_NOT_SUPPORTED 101 +#define ACPI_FADT_C3_NOT_SUPPORTED 1001
+/* FADT Feature Flags */ +#define ACPI_FADT_WBINVD (1 << 0) +#define ACPI_FADT_WBINVD_FLUSH (1 << 1) +#define ACPI_FADT_C1_SUPPORTED (1 << 2) +#define ACPI_FADT_C2_MP_SUPPORTED (1 << 3) +#define ACPI_FADT_POWER_BUTTON (1 << 4) +#define ACPI_FADT_SLEEP_BUTTON (1 << 5) +#define ACPI_FADT_FIXED_RTC (1 << 6) +#define ACPI_FADT_S4_RTC_WAKE (1 << 7) +#define ACPI_FADT_32BIT_TIMER (1 << 8) +#define ACPI_FADT_DOCKING_SUPPORTED (1 << 9) +#define ACPI_FADT_RESET_REGISTER (1 << 10) +#define ACPI_FADT_SEALED_CASE (1 << 11) +#define ACPI_FADT_HEADLESS (1 << 12) +#define ACPI_FADT_SLEEP_TYPE (1 << 13) +#define ACPI_FADT_PCI_EXPRESS_WAKE (1 << 14) +#define ACPI_FADT_PLATFORM_CLOCK (1 << 15) +#define ACPI_FADT_S4_RTC_VALID (1 << 16) +#define ACPI_FADT_REMOTE_POWER_ON (1 << 17) +#define ACPI_FADT_APIC_CLUSTER (1 << 18) +#define ACPI_FADT_APIC_PHYSICAL (1 << 19) +/* Bits 20-31: reserved ACPI 3.0 & 4.0 */ +#define ACPI_FADT_HW_REDUCED_ACPI (1 << 20) +#define ACPI_FADT_LOW_PWR_IDLE_S0 (1 << 21) +/* bits 22-31: reserved ACPI 5.0 */
Nits: could we use tab to between macro names, value and comments?
Addressed in patchset series v6.
+/* FADT Boot Architecture Flags */ +#define ACPI_FADT_LEGACY_DEVICES (1 << 0) +#define ACPI_FADT_8042 (1 << 1) +#define ACPI_FADT_VGA_NOT_PRESENT (1 << 2) +#define ACPI_FADT_MSI_NOT_SUPPORTED (1 << 3) +#define ACPI_FADT_NO_PCIE_ASPM_CONTROL (1 << 4) +#define ACPI_FADT_LEGACY_FREE 0x00 /* No legacy devices (including 8042) */
ditto.
Addressed in patchset series v6.
+/* FADT Preferred Power Management Profile */ +#define PM_UNSPECIFIED 0 +#define PM_DESKTOP 1 +#define PM_MOBILE 2 +#define PM_WORKSTATION 3 +#define PM_ENTERPRISE_SERVER 4 +#define PM_SOHO_SERVER 5 +#define PM_APPLIANCE_PC 6 +#define PM_PERFORMANCE_SERVER 7 +#define PM_TABLET 8, /* ACPI 5.0 */
ditto.
Addressed in patchset series v6.
+/* FACS (Firmware ACPI Control Structure) */ +struct acpi_facs {
char signature[4]; /* "FACS" */
u32 length; /* Length in bytes (>= 64) */
u32 hardware_signature; /* Hardware signature */
u32 firmware_waking_vector; /* Firmware waking vector */
u32 global_lock; /* Global lock */
u32 flags; /* FACS flags */
u32 x_firmware_waking_vector_l; /* X FW waking vector, low */
u32 x_firmware_waking_vector_h; /* X FW waking vector, high */
u8 version; /* ACPI 4.0: 2 */
u8 resv[31]; /* FIXME: 4.0: ospm_flags */
+};
+/* FACS flags */ +#define ACPI_FACS_S4BIOS_F (1 << 0) +#define ACPI_FACS_64BIT_WAKE_F (1 << 1) +/* Bits 31..2: reserved */
+/* These can be used by the target port. */
+unsigned long acpi_create_madt_lapics(unsigned long current); +int acpi_create_madt_ioapic(struct acpi_madt_ioapic *ioapic, u8 id, u32 addr,
Can we always use u32 for the parameters? like u32 id
These will make me change all the structure and recheck that nothing breaks since these values are getting assigned to the table structures directly. I do not think this makes any sense to have 4 bytes for something that can be fitted in 1 byte.
Defining it as a 8-bit parameter does not bring us any benefit, as it is passed via register or stacks where dword is the unit size. This is also required by Simon.
[snip]
Regards, Bin

This patch mainly adds ACPI support to QEMU. Verified by booting Linux kernel on QEMU i440FX and Q35.
Signed-off-by: Saket Sinha saket.sinha89@gmail.com ---
arch/x86/cpu/qemu/Makefile | 1 + arch/x86/cpu/qemu/acpi.c | 179 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 arch/x86/cpu/qemu/acpi.c
diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile index 9a66b16..8c3884c 100644 --- a/arch/x86/cpu/qemu/Makefile +++ b/arch/x86/cpu/qemu/Makefile @@ -8,4 +8,5 @@ ifndef CONFIG_EFI_STUB obj-y += car.o dram.o endif obj-y += qemu.o +obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.o obj-$(CONFIG_PCI) += pci.o diff --git a/arch/x86/cpu/qemu/acpi.c b/arch/x86/cpu/qemu/acpi.c new file mode 100644 index 0000000..7c981d0 --- /dev/null +++ b/arch/x86/cpu/qemu/acpi.c @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2015, Saket Sinha saket.sinha89@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include <common.h> +#include <asm/acpi_table.h> +#include <asm/ioapic.h> +#include <asm/tables.h> + +void acpi_create_fadt(struct acpi_fadt *fadt, struct acpi_facs *facs, + void *dsdt) +{ + acpi_header_t *header = &(fadt->header); + u16 pmbase; + + pci_dev_t bdf = PCI_BDF(0, 0x1f, 0); + pci_read_config_word(bdf, 0x40, &pmbase); + + /* + * TODO(saket.sinha89@gmail.com): wrong value + * of pmbase by above function. Harcoding it to + * correct value. Since no PCI register is + * programmed Power Management Interface is + * not working + */ + + pmbase = 0x0600; + + memset((void *)fadt, 0, sizeof(struct acpi_fadt)); + memcpy(header->signature, "FACP", 4); + header->length = sizeof(struct acpi_fadt); + header->revision = 3; + 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 = 0; + + fadt->firmware_ctrl = (unsigned long) facs; + fadt->dsdt = (unsigned long) dsdt; + fadt->model = 0x00; + fadt->preferred_pm_profile = PM_MOBILE; + fadt->sci_int = 0x9; + fadt->smi_cmd = 0; + fadt->acpi_enable = 0; + fadt->acpi_disable = 0; + fadt->s4bios_req = 0x0; + fadt->pstate_cnt = 0; + fadt->pm1a_evt_blk = pmbase; + fadt->pm1b_evt_blk = 0x0; + fadt->pm1a_cnt_blk = pmbase + 0x4; + fadt->pm1b_cnt_blk = 0x0; + fadt->pm2_cnt_blk = pmbase + 0x50; + fadt->pm_tmr_blk = pmbase + 0x8; + fadt->gpe0_blk = pmbase + 0x20; + fadt->gpe1_blk = 0; + fadt->pm1_evt_len = 4; + /* + * Upper word is reserved and + * Linux complains about 32 bit + */ + fadt->pm1_cnt_len = 2; + fadt->pm2_cnt_len = 1; + fadt->pm_tmr_len = 4; + fadt->gpe0_blk_len = 16; + fadt->gpe1_blk_len = 0; + fadt->gpe1_base = 0; + fadt->cst_cnt = 0; + fadt->p_lvl2_lat = 1; + fadt->p_lvl3_lat = 0x39; + fadt->flush_size = 0; + fadt->flush_stride = 0; + fadt->duty_offset = 1; + fadt->duty_width = 3; + fadt->day_alrm = 0xd; + fadt->mon_alrm = 0x00; + fadt->century = 0x32; + fadt->iapc_boot_arch = 0x00; + fadt->flags = ACPI_FADT_WBINVD | ACPI_FADT_C1_SUPPORTED | + ACPI_FADT_SLEEP_BUTTON | ACPI_FADT_S4_RTC_WAKE | + ACPI_FADT_DOCKING_SUPPORTED | ACPI_FADT_RESET_REGISTER | + ACPI_FADT_PLATFORM_CLOCK; + fadt->reset_reg.space_id = ACPI_ADDRESS_SPACE_IO; + fadt->reset_reg.bit_width = 8; + fadt->reset_reg.bit_offset = 0; + fadt->reset_reg.resv = 0; + fadt->reset_reg.addrl = 0xcf9; + fadt->reset_reg.addrh = 0; + fadt->reset_value = 0x06; + /* + * Set X_FIRMWARE_CTRL only if FACS is + * above 4GB. If X_FIRMWARE_CTRL is set, + * then FIRMWARE_CTRL must be zero + */ + fadt->x_firmware_ctl_l = 0; + fadt->x_firmware_ctl_h = 0; + fadt->x_dsdt_l = (unsigned long)dsdt; + fadt->x_dsdt_h = 0; + fadt->x_pm1a_evt_blk.space_id = 1; + fadt->x_pm1a_evt_blk.bit_width = 32; + fadt->x_pm1a_evt_blk.bit_offset = 0; + fadt->x_pm1a_evt_blk.resv = 0; + fadt->x_pm1a_evt_blk.addrl = pmbase; + fadt->x_pm1a_evt_blk.addrh = 0x0; + fadt->x_pm1b_evt_blk.space_id = 0; + fadt->x_pm1b_evt_blk.bit_width = 0; + fadt->x_pm1b_evt_blk.bit_offset = 0; + fadt->x_pm1b_evt_blk.resv = 0; + fadt->x_pm1b_evt_blk.addrl = 0x0; + fadt->x_pm1b_evt_blk.addrh = 0x0; + fadt->x_pm1a_cnt_blk.space_id = 1; + /* + * Upper word is reserved and + * Linux complains about 32 bit + */ + fadt->x_pm1a_cnt_blk.bit_width = 16; + fadt->x_pm1a_cnt_blk.bit_offset = 0; + fadt->x_pm1a_cnt_blk.resv = 0; + fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4; + fadt->x_pm1a_cnt_blk.addrh = 0x0; + fadt->x_pm1b_cnt_blk.space_id = 0; + fadt->x_pm1b_cnt_blk.bit_width = 0; + fadt->x_pm1b_cnt_blk.bit_offset = 0; + fadt->x_pm1b_cnt_blk.resv = 0; + fadt->x_pm1b_cnt_blk.addrl = 0x0; + fadt->x_pm1b_cnt_blk.addrh = 0x0; + fadt->x_pm2_cnt_blk.space_id = 1; + fadt->x_pm2_cnt_blk.bit_width = 8; + fadt->x_pm2_cnt_blk.bit_offset = 0; + fadt->x_pm2_cnt_blk.resv = 0; + fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50; + fadt->x_pm2_cnt_blk.addrh = 0x0; + fadt->x_pm_tmr_blk.space_id = 1; + fadt->x_pm_tmr_blk.bit_width = 32; + fadt->x_pm_tmr_blk.bit_offset = 0; + fadt->x_pm_tmr_blk.resv = 0; + fadt->x_pm_tmr_blk.addrl = pmbase + 0x8; + fadt->x_pm_tmr_blk.addrh = 0x0; + fadt->x_gpe0_blk.space_id = 1; + fadt->x_gpe0_blk.bit_width = 128; + fadt->x_gpe0_blk.bit_offset = 0; + fadt->x_gpe0_blk.resv = 0; + fadt->x_gpe0_blk.addrl = pmbase + 0x20; + fadt->x_gpe0_blk.addrh = 0x0; + fadt->x_gpe1_blk.space_id = 0; + fadt->x_gpe1_blk.bit_width = 0; + fadt->x_gpe1_blk.bit_offset = 0; + fadt->x_gpe1_blk.resv = 0; + fadt->x_gpe1_blk.addrl = 0x0; + fadt->x_gpe1_blk.addrh = 0x0; + + header->checksum = + table_compute_checksum((void *)fadt, header->length); +} + +unsigned long acpi_fill_madt(unsigned long current) +{ + /* create all subtables for processors */ + current = acpi_create_madt_lapics(current); + + /* + * TODO(saket.sinha89@gmail.com): get these + * IRQ values from device tree + */ + current += acpi_create_madt_ioapic + ((struct acpi_madt_ioapic *)current, 2, IO_APIC_ADDR, 0); + current += acpi_create_madt_irqoverride + ((struct acpi_madt_irqoverride *)current, 0, 0, 2, 0); + current += acpi_create_madt_irqoverride + ((struct acpi_madt_irqoverride *)current, 0, 9, 9, 0xD); + current += acpi_create_madt_irqoverride + ((struct acpi_madt_irqoverride *)current, 0, 0xB, 0xB, 0xD); + acpi_create_madt_lapic_nmi + ((struct acpi_madt_lapic_nmi *)current, 0, 0, 0); + + return current; +} +

Hi Saket,
On Tue, Aug 18, 2015 at 3:29 AM, Saket Sinha saket.sinha89@gmail.com wrote:
This patch mainly adds ACPI support to QEMU. Verified by booting Linux kernel on QEMU i440FX and Q35.
Signed-off-by: Saket Sinha saket.sinha89@gmail.com
arch/x86/cpu/qemu/Makefile | 1 + arch/x86/cpu/qemu/acpi.c | 179 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 arch/x86/cpu/qemu/acpi.c
diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile index 9a66b16..8c3884c 100644 --- a/arch/x86/cpu/qemu/Makefile +++ b/arch/x86/cpu/qemu/Makefile @@ -8,4 +8,5 @@ ifndef CONFIG_EFI_STUB obj-y += car.o dram.o endif obj-y += qemu.o +obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.o obj-$(CONFIG_PCI) += pci.o diff --git a/arch/x86/cpu/qemu/acpi.c b/arch/x86/cpu/qemu/acpi.c new file mode 100644 index 0000000..7c981d0 --- /dev/null +++ b/arch/x86/cpu/qemu/acpi.c @@ -0,0 +1,179 @@ +/*
- Copyright (C) 2015, Saket Sinha saket.sinha89@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <asm/acpi_table.h> +#include <asm/ioapic.h> +#include <asm/tables.h>
+void acpi_create_fadt(struct acpi_fadt *fadt, struct acpi_facs *facs,
void *dsdt)
+{
acpi_header_t *header = &(fadt->header);
u16 pmbase;
pci_dev_t bdf = PCI_BDF(0, 0x1f, 0);
pci_read_config_word(bdf, 0x40, &pmbase);
/*
* TODO(saket.sinha89@gmail.com): wrong value
* of pmbase by above function. Harcoding it to
* correct value. Since no PCI register is
* programmed Power Management Interface is
* not working
*/
Given you already know the root cause here (PMBASE is not programmed), can you program this register in the QEMU codes to make it work? And you can check arch/x86/cpu/quark/Kconfig to use common names for these ACPI register blocks, like the one used in quark. (I remember I mentioned this comment before)
pmbase = 0x0600;
memset((void *)fadt, 0, sizeof(struct acpi_fadt));
memcpy(header->signature, "FACP", 4);
header->length = sizeof(struct acpi_fadt);
header->revision = 3;
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 = 0;
fadt->firmware_ctrl = (unsigned long) facs;
fadt->dsdt = (unsigned long) dsdt;
fadt->model = 0x00;
fadt->preferred_pm_profile = PM_MOBILE;
fadt->sci_int = 0x9;
fadt->smi_cmd = 0;
fadt->acpi_enable = 0;
fadt->acpi_disable = 0;
fadt->s4bios_req = 0x0;
fadt->pstate_cnt = 0;
fadt->pm1a_evt_blk = pmbase;
fadt->pm1b_evt_blk = 0x0;
fadt->pm1a_cnt_blk = pmbase + 0x4;
fadt->pm1b_cnt_blk = 0x0;
fadt->pm2_cnt_blk = pmbase + 0x50;
fadt->pm_tmr_blk = pmbase + 0x8;
fadt->gpe0_blk = pmbase + 0x20;
fadt->gpe1_blk = 0;
fadt->pm1_evt_len = 4;
/*
* Upper word is reserved and
* Linux complains about 32 bit
*/
fadt->pm1_cnt_len = 2;
fadt->pm2_cnt_len = 1;
fadt->pm_tmr_len = 4;
fadt->gpe0_blk_len = 16;
fadt->gpe1_blk_len = 0;
fadt->gpe1_base = 0;
fadt->cst_cnt = 0;
fadt->p_lvl2_lat = 1;
fadt->p_lvl3_lat = 0x39;
fadt->flush_size = 0;
fadt->flush_stride = 0;
fadt->duty_offset = 1;
fadt->duty_width = 3;
fadt->day_alrm = 0xd;
fadt->mon_alrm = 0x00;
fadt->century = 0x32;
fadt->iapc_boot_arch = 0x00;
fadt->flags = ACPI_FADT_WBINVD | ACPI_FADT_C1_SUPPORTED |
ACPI_FADT_SLEEP_BUTTON | ACPI_FADT_S4_RTC_WAKE |
ACPI_FADT_DOCKING_SUPPORTED | ACPI_FADT_RESET_REGISTER |
ACPI_FADT_PLATFORM_CLOCK;
fadt->reset_reg.space_id = ACPI_ADDRESS_SPACE_IO;
fadt->reset_reg.bit_width = 8;
fadt->reset_reg.bit_offset = 0;
fadt->reset_reg.resv = 0;
fadt->reset_reg.addrl = 0xcf9;
fadt->reset_reg.addrh = 0;
fadt->reset_value = 0x06;
/*
* Set X_FIRMWARE_CTRL only if FACS is
* above 4GB. If X_FIRMWARE_CTRL is set,
* then FIRMWARE_CTRL must be zero
*/
fadt->x_firmware_ctl_l = 0;
fadt->x_firmware_ctl_h = 0;
fadt->x_dsdt_l = (unsigned long)dsdt;
fadt->x_dsdt_h = 0;
fadt->x_pm1a_evt_blk.space_id = 1;
fadt->x_pm1a_evt_blk.bit_width = 32;
fadt->x_pm1a_evt_blk.bit_offset = 0;
fadt->x_pm1a_evt_blk.resv = 0;
fadt->x_pm1a_evt_blk.addrl = pmbase;
fadt->x_pm1a_evt_blk.addrh = 0x0;
fadt->x_pm1b_evt_blk.space_id = 0;
fadt->x_pm1b_evt_blk.bit_width = 0;
fadt->x_pm1b_evt_blk.bit_offset = 0;
fadt->x_pm1b_evt_blk.resv = 0;
fadt->x_pm1b_evt_blk.addrl = 0x0;
fadt->x_pm1b_evt_blk.addrh = 0x0;
fadt->x_pm1a_cnt_blk.space_id = 1;
/*
* Upper word is reserved and
* Linux complains about 32 bit
*/
fadt->x_pm1a_cnt_blk.bit_width = 16;
fadt->x_pm1a_cnt_blk.bit_offset = 0;
fadt->x_pm1a_cnt_blk.resv = 0;
fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4;
fadt->x_pm1a_cnt_blk.addrh = 0x0;
fadt->x_pm1b_cnt_blk.space_id = 0;
fadt->x_pm1b_cnt_blk.bit_width = 0;
fadt->x_pm1b_cnt_blk.bit_offset = 0;
fadt->x_pm1b_cnt_blk.resv = 0;
fadt->x_pm1b_cnt_blk.addrl = 0x0;
fadt->x_pm1b_cnt_blk.addrh = 0x0;
fadt->x_pm2_cnt_blk.space_id = 1;
fadt->x_pm2_cnt_blk.bit_width = 8;
fadt->x_pm2_cnt_blk.bit_offset = 0;
fadt->x_pm2_cnt_blk.resv = 0;
fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50;
fadt->x_pm2_cnt_blk.addrh = 0x0;
fadt->x_pm_tmr_blk.space_id = 1;
fadt->x_pm_tmr_blk.bit_width = 32;
fadt->x_pm_tmr_blk.bit_offset = 0;
fadt->x_pm_tmr_blk.resv = 0;
fadt->x_pm_tmr_blk.addrl = pmbase + 0x8;
fadt->x_pm_tmr_blk.addrh = 0x0;
fadt->x_gpe0_blk.space_id = 1;
fadt->x_gpe0_blk.bit_width = 128;
fadt->x_gpe0_blk.bit_offset = 0;
fadt->x_gpe0_blk.resv = 0;
fadt->x_gpe0_blk.addrl = pmbase + 0x20;
fadt->x_gpe0_blk.addrh = 0x0;
fadt->x_gpe1_blk.space_id = 0;
fadt->x_gpe1_blk.bit_width = 0;
fadt->x_gpe1_blk.bit_offset = 0;
fadt->x_gpe1_blk.resv = 0;
fadt->x_gpe1_blk.addrl = 0x0;
fadt->x_gpe1_blk.addrh = 0x0;
header->checksum =
table_compute_checksum((void *)fadt, header->length);
+}
+unsigned long acpi_fill_madt(unsigned long current) +{
/* create all subtables for processors */
current = acpi_create_madt_lapics(current);
/*
* TODO(saket.sinha89@gmail.com): get these
* IRQ values from device tree
*/
current += acpi_create_madt_ioapic
((struct acpi_madt_ioapic *)current, 2, IO_APIC_ADDR, 0);
current += acpi_create_madt_irqoverride
((struct acpi_madt_irqoverride *)current, 0, 0, 2, 0);
current += acpi_create_madt_irqoverride
((struct acpi_madt_irqoverride *)current, 0, 9, 9, 0xD);
current += acpi_create_madt_irqoverride
((struct acpi_madt_irqoverride *)current, 0, 0xB, 0xB, 0xD);
Nits: please use lower case hex numbers.
acpi_create_madt_lapic_nmi
((struct acpi_madt_lapic_nmi *)current, 0, 0, 0);
return current;
+}
--
Regards, Bin

Hi Bin,
Please find my response inline.
On Tue, Aug 18, 2015 at 12:36 PM, Bin Meng bmeng.cn@gmail.com wrote:
Hi Saket,
On Tue, Aug 18, 2015 at 3:29 AM, Saket Sinha saket.sinha89@gmail.com wrote:
This patch mainly adds ACPI support to QEMU. Verified by booting Linux kernel on QEMU i440FX and Q35.
Signed-off-by: Saket Sinha saket.sinha89@gmail.com
arch/x86/cpu/qemu/Makefile | 1 + arch/x86/cpu/qemu/acpi.c | 179 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 arch/x86/cpu/qemu/acpi.c
diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile index 9a66b16..8c3884c 100644 --- a/arch/x86/cpu/qemu/Makefile +++ b/arch/x86/cpu/qemu/Makefile @@ -8,4 +8,5 @@ ifndef CONFIG_EFI_STUB obj-y += car.o dram.o endif obj-y += qemu.o +obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.o obj-$(CONFIG_PCI) += pci.o diff --git a/arch/x86/cpu/qemu/acpi.c b/arch/x86/cpu/qemu/acpi.c new file mode 100644 index 0000000..7c981d0 --- /dev/null +++ b/arch/x86/cpu/qemu/acpi.c @@ -0,0 +1,179 @@ +/*
- Copyright (C) 2015, Saket Sinha saket.sinha89@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <asm/acpi_table.h> +#include <asm/ioapic.h> +#include <asm/tables.h>
+void acpi_create_fadt(struct acpi_fadt *fadt, struct acpi_facs *facs,
void *dsdt)
+{
acpi_header_t *header = &(fadt->header);
u16 pmbase;
pci_dev_t bdf = PCI_BDF(0, 0x1f, 0);
pci_read_config_word(bdf, 0x40, &pmbase);
/*
* TODO(saket.sinha89@gmail.com): wrong value
* of pmbase by above function. Harcoding it to
* correct value. Since no PCI register is
* programmed Power Management Interface is
* not working
*/
Given you already know the root cause here (PMBASE is not programmed), can you program this register in the QEMU codes to make it work?
Please elaborate on this. Do you want me to hack QEMU code to verify that it works ?
you can check arch/x86/cpu/quark/Kconfig to use common names for these ACPI register blocks, like the one used in quark. (I remember I mentioned this comment before)
This is not clear. I know these registers are defined in arch/x86/cpu/quark/Kconfig where configurable values can be assigned to it. But here I am trying to create fadt table structure which have these registers for sure but I am trying to fill those values after reading them from the hardware( in our case QEMU)
pmbase = 0x0600;
memset((void *)fadt, 0, sizeof(struct acpi_fadt));
memcpy(header->signature, "FACP", 4);
header->length = sizeof(struct acpi_fadt);
header->revision = 3;
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 = 0;
fadt->firmware_ctrl = (unsigned long) facs;
fadt->dsdt = (unsigned long) dsdt;
fadt->model = 0x00;
fadt->preferred_pm_profile = PM_MOBILE;
fadt->sci_int = 0x9;
fadt->smi_cmd = 0;
fadt->acpi_enable = 0;
fadt->acpi_disable = 0;
fadt->s4bios_req = 0x0;
fadt->pstate_cnt = 0;
fadt->pm1a_evt_blk = pmbase;
fadt->pm1b_evt_blk = 0x0;
fadt->pm1a_cnt_blk = pmbase + 0x4;
fadt->pm1b_cnt_blk = 0x0;
fadt->pm2_cnt_blk = pmbase + 0x50;
fadt->pm_tmr_blk = pmbase + 0x8;
fadt->gpe0_blk = pmbase + 0x20;
fadt->gpe1_blk = 0;
fadt->pm1_evt_len = 4;
/*
* Upper word is reserved and
* Linux complains about 32 bit
*/
fadt->pm1_cnt_len = 2;
fadt->pm2_cnt_len = 1;
fadt->pm_tmr_len = 4;
fadt->gpe0_blk_len = 16;
fadt->gpe1_blk_len = 0;
fadt->gpe1_base = 0;
fadt->cst_cnt = 0;
fadt->p_lvl2_lat = 1;
fadt->p_lvl3_lat = 0x39;
fadt->flush_size = 0;
fadt->flush_stride = 0;
fadt->duty_offset = 1;
fadt->duty_width = 3;
fadt->day_alrm = 0xd;
fadt->mon_alrm = 0x00;
fadt->century = 0x32;
fadt->iapc_boot_arch = 0x00;
fadt->flags = ACPI_FADT_WBINVD | ACPI_FADT_C1_SUPPORTED |
ACPI_FADT_SLEEP_BUTTON | ACPI_FADT_S4_RTC_WAKE |
ACPI_FADT_DOCKING_SUPPORTED | ACPI_FADT_RESET_REGISTER |
ACPI_FADT_PLATFORM_CLOCK;
fadt->reset_reg.space_id = ACPI_ADDRESS_SPACE_IO;
fadt->reset_reg.bit_width = 8;
fadt->reset_reg.bit_offset = 0;
fadt->reset_reg.resv = 0;
fadt->reset_reg.addrl = 0xcf9;
fadt->reset_reg.addrh = 0;
fadt->reset_value = 0x06;
/*
* Set X_FIRMWARE_CTRL only if FACS is
* above 4GB. If X_FIRMWARE_CTRL is set,
* then FIRMWARE_CTRL must be zero
*/
fadt->x_firmware_ctl_l = 0;
fadt->x_firmware_ctl_h = 0;
fadt->x_dsdt_l = (unsigned long)dsdt;
fadt->x_dsdt_h = 0;
fadt->x_pm1a_evt_blk.space_id = 1;
fadt->x_pm1a_evt_blk.bit_width = 32;
fadt->x_pm1a_evt_blk.bit_offset = 0;
fadt->x_pm1a_evt_blk.resv = 0;
fadt->x_pm1a_evt_blk.addrl = pmbase;
fadt->x_pm1a_evt_blk.addrh = 0x0;
fadt->x_pm1b_evt_blk.space_id = 0;
fadt->x_pm1b_evt_blk.bit_width = 0;
fadt->x_pm1b_evt_blk.bit_offset = 0;
fadt->x_pm1b_evt_blk.resv = 0;
fadt->x_pm1b_evt_blk.addrl = 0x0;
fadt->x_pm1b_evt_blk.addrh = 0x0;
fadt->x_pm1a_cnt_blk.space_id = 1;
/*
* Upper word is reserved and
* Linux complains about 32 bit
*/
fadt->x_pm1a_cnt_blk.bit_width = 16;
fadt->x_pm1a_cnt_blk.bit_offset = 0;
fadt->x_pm1a_cnt_blk.resv = 0;
fadt->x_pm1a_cnt_blk.addrl = pmbase + 0x4;
fadt->x_pm1a_cnt_blk.addrh = 0x0;
fadt->x_pm1b_cnt_blk.space_id = 0;
fadt->x_pm1b_cnt_blk.bit_width = 0;
fadt->x_pm1b_cnt_blk.bit_offset = 0;
fadt->x_pm1b_cnt_blk.resv = 0;
fadt->x_pm1b_cnt_blk.addrl = 0x0;
fadt->x_pm1b_cnt_blk.addrh = 0x0;
fadt->x_pm2_cnt_blk.space_id = 1;
fadt->x_pm2_cnt_blk.bit_width = 8;
fadt->x_pm2_cnt_blk.bit_offset = 0;
fadt->x_pm2_cnt_blk.resv = 0;
fadt->x_pm2_cnt_blk.addrl = pmbase + 0x50;
fadt->x_pm2_cnt_blk.addrh = 0x0;
fadt->x_pm_tmr_blk.space_id = 1;
fadt->x_pm_tmr_blk.bit_width = 32;
fadt->x_pm_tmr_blk.bit_offset = 0;
fadt->x_pm_tmr_blk.resv = 0;
fadt->x_pm_tmr_blk.addrl = pmbase + 0x8;
fadt->x_pm_tmr_blk.addrh = 0x0;
fadt->x_gpe0_blk.space_id = 1;
fadt->x_gpe0_blk.bit_width = 128;
fadt->x_gpe0_blk.bit_offset = 0;
fadt->x_gpe0_blk.resv = 0;
fadt->x_gpe0_blk.addrl = pmbase + 0x20;
fadt->x_gpe0_blk.addrh = 0x0;
fadt->x_gpe1_blk.space_id = 0;
fadt->x_gpe1_blk.bit_width = 0;
fadt->x_gpe1_blk.bit_offset = 0;
fadt->x_gpe1_blk.resv = 0;
fadt->x_gpe1_blk.addrl = 0x0;
fadt->x_gpe1_blk.addrh = 0x0;
header->checksum =
table_compute_checksum((void *)fadt, header->length);
+}
+unsigned long acpi_fill_madt(unsigned long current) +{
/* create all subtables for processors */
current = acpi_create_madt_lapics(current);
/*
* TODO(saket.sinha89@gmail.com): get these
* IRQ values from device tree
*/
current += acpi_create_madt_ioapic
((struct acpi_madt_ioapic *)current, 2, IO_APIC_ADDR, 0);
current += acpi_create_madt_irqoverride
((struct acpi_madt_irqoverride *)current, 0, 0, 2, 0);
current += acpi_create_madt_irqoverride
((struct acpi_madt_irqoverride *)current, 0, 9, 9, 0xD);
current += acpi_create_madt_irqoverride
((struct acpi_madt_irqoverride *)current, 0, 0xB, 0xB, 0xD);
Nits: please use lower case hex numbers.
Addressed in patchset series v6.
acpi_create_madt_lapic_nmi
((struct acpi_madt_lapic_nmi *)current, 0, 0, 0);
return current;
+}
--
Regards, Bin
Regards, Saket Sinha

Hi Saket,
On Fri, Aug 21, 2015 at 12:24 PM, Saket Sinha saket.sinha89@gmail.com wrote:
Hi Bin,
Please find my response inline.
On Tue, Aug 18, 2015 at 12:36 PM, Bin Meng bmeng.cn@gmail.com wrote:
Hi Saket,
On Tue, Aug 18, 2015 at 3:29 AM, Saket Sinha saket.sinha89@gmail.com wrote:
This patch mainly adds ACPI support to QEMU. Verified by booting Linux kernel on QEMU i440FX and Q35.
Signed-off-by: Saket Sinha saket.sinha89@gmail.com
arch/x86/cpu/qemu/Makefile | 1 + arch/x86/cpu/qemu/acpi.c | 179 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 arch/x86/cpu/qemu/acpi.c
diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile index 9a66b16..8c3884c 100644 --- a/arch/x86/cpu/qemu/Makefile +++ b/arch/x86/cpu/qemu/Makefile @@ -8,4 +8,5 @@ ifndef CONFIG_EFI_STUB obj-y += car.o dram.o endif obj-y += qemu.o +obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.o obj-$(CONFIG_PCI) += pci.o diff --git a/arch/x86/cpu/qemu/acpi.c b/arch/x86/cpu/qemu/acpi.c new file mode 100644 index 0000000..7c981d0 --- /dev/null +++ b/arch/x86/cpu/qemu/acpi.c @@ -0,0 +1,179 @@ +/*
- Copyright (C) 2015, Saket Sinha saket.sinha89@gmail.com
- SPDX-License-Identifier: GPL-2.0+
- */
+#include <common.h> +#include <asm/acpi_table.h> +#include <asm/ioapic.h> +#include <asm/tables.h>
+void acpi_create_fadt(struct acpi_fadt *fadt, struct acpi_facs *facs,
void *dsdt)
+{
acpi_header_t *header = &(fadt->header);
u16 pmbase;
pci_dev_t bdf = PCI_BDF(0, 0x1f, 0);
pci_read_config_word(bdf, 0x40, &pmbase);
/*
* TODO(saket.sinha89@gmail.com): wrong value
* of pmbase by above function. Harcoding it to
* correct value. Since no PCI register is
* programmed Power Management Interface is
* not working
*/
Given you already know the root cause here (PMBASE is not programmed), can you program this register in the QEMU codes to make it work?
Please elaborate on this. Do you want me to hack QEMU code to verify that it works ?
Based on your TODO comment, you already found the root cause, right? Then why don't you support that? Yes, please add QEMU code to program that register.
you can check arch/x86/cpu/quark/Kconfig to use common names for these ACPI register blocks, like the one used in quark. (I remember I mentioned this comment before)
This is not clear. I know these registers are defined in arch/x86/cpu/quark/Kconfig where configurable values can be assigned to it. But here I am trying to create fadt table structure which have these registers for sure but I am trying to fill those values after reading them from the hardware( in our case QEMU)
I mean you can use generic macro names (which is the common names for all x86 boards), and if x86 boards support ACPI, it needs to use that macro to program its registers. And in your common codes, you don't need care which register it is on that specific platform, like CONFIG_PCIE_ECAM_BASE does.
[snip]
Regards, Bin

The DSDT table contains a bytecode that is executed by a driver in the kernel.
Signed-off-by: Saket Sinha saket.sinha89@gmail.com ---
arch/x86/cpu/qemu/Makefile | 2 +- arch/x86/cpu/qemu/acpi/cpu-hotplug.asl | 78 +++++++ arch/x86/cpu/qemu/acpi/dbug.asl | 26 +++ arch/x86/cpu/qemu/acpi/hpet.asl | 33 +++ arch/x86/cpu/qemu/acpi/isa.asl | 102 ++++++++ arch/x86/cpu/qemu/acpi/pci-crs.asl | 61 +++++ arch/x86/cpu/qemu/dsdt.asl | 414 +++++++++++++++++++++++++++++++++ 7 files changed, 715 insertions(+), 1 deletion(-) create mode 100644 arch/x86/cpu/qemu/acpi/cpu-hotplug.asl create mode 100644 arch/x86/cpu/qemu/acpi/dbug.asl create mode 100644 arch/x86/cpu/qemu/acpi/hpet.asl create mode 100644 arch/x86/cpu/qemu/acpi/isa.asl create mode 100644 arch/x86/cpu/qemu/acpi/pci-crs.asl create mode 100644 arch/x86/cpu/qemu/dsdt.asl
diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile index 8c3884c..1c00d1d 100644 --- a/arch/x86/cpu/qemu/Makefile +++ b/arch/x86/cpu/qemu/Makefile @@ -8,5 +8,5 @@ ifndef CONFIG_EFI_STUB obj-y += car.o dram.o endif obj-y += qemu.o -obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.o +obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.o dsdt.o obj-$(CONFIG_PCI) += pci.o diff --git a/arch/x86/cpu/qemu/acpi/cpu-hotplug.asl b/arch/x86/cpu/qemu/acpi/cpu-hotplug.asl new file mode 100644 index 0000000..15b40a4 --- /dev/null +++ b/arch/x86/cpu/qemu/acpi/cpu-hotplug.asl @@ -0,0 +1,78 @@ +/**************************************************************** + * CPU hotplug + ****************************************************************/ + +Scope(_SB) { + /* Objects filled in by run-time generated SSDT */ + External(NTFY, MethodObj) + External(CPON, PkgObj) + + /* Methods called by run-time generated SSDT Processor objects */ + Method(CPMA, 1, NotSerialized) { + /* _MAT method - create an madt apic buffer + Arg0 = Processor ID = Local APIC ID + Local0 = CPON flag for this cpu */ + Store(DerefOf(Index(CPON, Arg0)), Local0) + /* Local1 = Buffer (in madt apic form) to return */ + Store(Buffer(8) {0x00, 0x08, 0x00, 0x00, 0x00, 0, 0, 0}, Local1) + /* Update the processor id, lapic id, and enable/disable status */ + Store(Arg0, Index(Local1, 2)) + Store(Arg0, Index(Local1, 3)) + Store(Local0, Index(Local1, 4)) + Return (Local1) + } + Method(CPST, 1, NotSerialized) { + /* _STA method - return ON status of cpu + Arg0 = Processor ID = Local APIC ID + Local0 = CPON flag for this cpu */ + Store(DerefOf(Index(CPON, Arg0)), Local0) + If (Local0) { + Return (0xf) + } Else { + Return (0x0) + } + } + Method(CPEJ, 2, NotSerialized) { + /* _EJ0 method - eject callback */ + Sleep(200) + } + + /* CPU hotplug notify method */ + OperationRegion(PRST, SystemIO, 0xaf00, 32) + Field(PRST, ByteAcc, NoLock, Preserve) { + PRS, 256 + } + Method(PRSC, 0) { + /* Local5 = active cpu bitmap */ + Store(PRS, Local5) + /* Local2 = last read byte from bitmap */ + Store(Zero, Local2) + /* Local0 = Processor ID / APIC ID iterator */ + Store(Zero, Local0) + While (LLess(Local0, SizeOf(CPON))) { + /* Local1 = CPON flag for this cpu */ + Store(DerefOf(Index(CPON, Local0)), Local1) + If (And(Local0, 0x07)) { + /* Shift down previously read bitmap byte */ + ShiftRight(Local2, 1, Local2) + } Else { + /* Read next byte from cpu bitmap */ + Store(DerefOf(Index(Local5, ShiftRight(Local0, 3))), Local2) + } + /* Local3 = active state for this cpu */ + Store(And(Local2, 1), Local3) + + If (LNotEqual(Local1, Local3)) { + /* State change - update CPON with new state */ + Store(Local3, Index(CPON, Local0)) + /* Do CPU notify */ + If (LEqual(Local3, 1)) { + NTFY(Local0, 1) + } Else { + NTFY(Local0, 3) + } + } + Increment(Local0) + } + } +} diff --git a/arch/x86/cpu/qemu/acpi/dbug.asl b/arch/x86/cpu/qemu/acpi/dbug.asl new file mode 100644 index 0000000..55c932a --- /dev/null +++ b/arch/x86/cpu/qemu/acpi/dbug.asl @@ -0,0 +1,26 @@ +/**************************************************************** + * Debugging + ****************************************************************/ + +Scope() { + /* Debug Output */ + OperationRegion(DBG, SystemIO, 0x0402, 0x01) + Field(DBG, ByteAcc, NoLock, Preserve) { + DBGB, 8, + } + + /* Debug method - use this method to send output to the QEMU + * BIOS debug port. This method handles strings, integers, + * and buffers. For example: DBUG("abc") DBUG(0x123) */ + Method(DBUG, 1) { + ToHexString(Arg0, Local0) + ToBuffer(Local0, Local0) + Subtract(SizeOf(Local0), 1, Local1) + Store(Zero, Local2) + While (LLess(Local2, Local1)) { + Store(DerefOf(Index(Local0, Local2)), DBGB) + Increment(Local2) + } + Store(0x0a, dbgb) + } +} diff --git a/arch/x86/cpu/qemu/acpi/hpet.asl b/arch/x86/cpu/qemu/acpi/hpet.asl new file mode 100644 index 0000000..4251580 --- /dev/null +++ b/arch/x86/cpu/qemu/acpi/hpet.asl @@ -0,0 +1,33 @@ +/**************************************************************** + * HPET + ****************************************************************/ + +Scope(_SB) { + Device(HPET) { + Name(_HID, EISAID("PNP0103")) + Name(_UID, 0) + OperationRegion(HPTM, SystemMemory, 0xfed00000, 0x400) + Field(HPTM, DWordAcc, Lock, Preserve) { + VEND, 32, + PRD, 32, + } + Method(_STA, 0, NotSerialized) { + Store(VEND, Local0) + Store(PRD, Local1) + ShiftRight(Local0, 16, Local0) + If (LOr(LEqual(Local0, 0), LEqual(Local0, 0xffff))) { + Return (0x0) + } + If (LOr(LEqual(Local1, 0), LGreater(Local1, 100000000))) { + Return (0x0) + } + Return (0x0f) + } + Name(_CRS, ResourceTemplate() { + Memory32Fixed(ReadOnly, + 0xfed00000, /* Address Base */ + 0x00000400, /* Address Length */ + ) + }) + } +} diff --git a/arch/x86/cpu/qemu/acpi/isa.asl b/arch/x86/cpu/qemu/acpi/isa.asl new file mode 100644 index 0000000..d6b3d9b --- /dev/null +++ b/arch/x86/cpu/qemu/acpi/isa.asl @@ -0,0 +1,102 @@ +/* Common legacy ISA style devices. */ +Scope(_SB.PCI0.ISA) { + + Device(RTC) { + Name(_HID, EisaId("PNP0B00")) + Name(_CRS, ResourceTemplate() { + IO(Decode16, 0x0070, 0x0070, 0x10, 0x02) + IRQNoFlags() { 8 } + IO(Decode16, 0x0072, 0x0072, 0x02, 0x06) + }) + } + + Device(KBD) { + Name(_HID, EisaId("PNP0303")) + Method(_STA, 0, NotSerialized) { + Return (0x0f) + } + Name(_CRS, ResourceTemplate() { + IO(Decode16, 0x0060, 0x0060, 0x01, 0x01) + IO(Decode16, 0x0064, 0x0064, 0x01, 0x01) + IRQNoFlags() { 1 } + }) + } + + Device(MOU) { + Name(_HID, EisaId("PNP0F13")) + Method(_STA, 0, NotSerialized) { + Return (0x0f) + } + Name(_CRS, ResourceTemplate() { + IRQNoFlags() { 12 } + }) + } + + Device(FDC0) { + Name(_HID, EisaId("PNP0700")) + Method(_STA, 0, NotSerialized) { + Store(FDEN, Local0) + If (LEqual(Local0, 0)) { + Return (0x00) + } Else { + Return (0x0f) + } + } + Name(_CRS, ResourceTemplate() { + IO(Decode16, 0x03f2, 0x03f2, 0x00, 0x04) + IO(Decode16, 0x03f7, 0x03f7, 0x00, 0x01) + IRQNoFlags() { 6 } + DMA(Compatibility, NotBusMaster, Transfer8) { 2 } + }) + } + + Device(LPT) { + Name(_HID, EisaId("PNP0400")) + Method(_STA, 0, NotSerialized) { + Store(LPEN, Local0) + If (LEqual(Local0, 0)) { + Return (0x00) + } Else { + Return (0x0f) + } + } + Name(_CRS, ResourceTemplate() { + IO(Decode16, 0x0378, 0x0378, 0x08, 0x08) + IRQNoFlags() { 7 } + }) + } + + Device(COM1) { + Name(_HID, EisaId("PNP0501")) + Name(_UID, 0x01) + Method(_STA, 0, NotSerialized) { + Store(CAEN, Local0) + If (LEqual(Local0, 0)) { + Return (0x00) + } Else { + Return (0x0f) + } + } + Name(_CRS, ResourceTemplate() { + IO(Decode16, 0x03f8, 0x03f8, 0x00, 0x08) + IRQNoFlags() { 4 } + }) + } + + Device(COM2) { + Name(_HID, EisaId("PNP0501")) + Name(_UID, 0x02) + Method(_STA, 0, NotSerialized) { + Store(CBEN, Local0) + If (LEqual(Local0, 0)) { + Return (0x00) + } Else { + Return (0x0f) + } + } + Name(_CRS, ResourceTemplate() { + IO(Decode16, 0x02f8, 0x02f8, 0x00, 0x08) + IRQNoFlags() { 3 } + }) + } +} diff --git a/arch/x86/cpu/qemu/acpi/pci-crs.asl b/arch/x86/cpu/qemu/acpi/pci-crs.asl new file mode 100644 index 0000000..43b2858 --- /dev/null +++ b/arch/x86/cpu/qemu/acpi/pci-crs.asl @@ -0,0 +1,61 @@ +/* PCI CRS (current resources) definition. */ +Scope(_SB.PCI0) { + + Name(CRES, ResourceTemplate() { + WordBusNumber(ResourceProducer, MinFixed, MaxFixed, PosDecode, + 0x0000, /* Address Space Granularity */ + 0x0000, /* Address Range Minimum */ + 0x00ff, /* Address Range Maximum */ + 0x0000, /* Address Translation Offset */ + 0x0100, /* Address Length */ + ,, ) + IO(Decode16, + 0x0cf8, /* Address Range Minimum */ + 0x0cf8, /* Address Range Maximum */ + 0x01, /* Address Alignment */ + 0x08, /* Address Length */ + ) + WordIO(ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x0000, /* Address Space Granularity */ + 0x0000, /* Address Range Minimum */ + 0x0cf7, /* Address Range Maximum */ + 0x0000, /* Address Translation Offset */ + 0x0cf8, /* Address Length */ + ,, , TypeStatic) + WordIO(ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange, + 0x0000, /* Address Space Granularity */ + 0x0d00, /* Address Range Minimum */ + 0xffff, /* Address Range Maximum */ + 0x0000, /* Address Translation Offset */ + 0xf300, /* Address Length */ + ,, , TypeStatic) + DWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, + 0x00000000, /* Address Space Granularity */ + 0x000a0000, /* Address Range Minimum */ + 0x000bffff, /* Address Range Maximum */ + 0x00000000, /* Address Translation Offset */ + 0x00020000, /* Address Length */ + ,, , AddressRangeMemory, TypeStatic) + DWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite, + 0x00000000, /* Address Space Granularity */ + 0xe0000000, /* Address Range Minimum */ + 0xfebfffff, /* Address Range Maximum */ + 0x00000000, /* Address Translation Offset */ + 0x1ec00000, /* Address Length */ + ,, PW32, AddressRangeMemory, TypeStatic) + }) + + Name(CR64, ResourceTemplate() { + QWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite, + 0x00000000, /* Address Space Granularity */ + 0x8000000000, /* Address Range Minimum */ + 0xffffffff, /* Address Range Maximum */ + 0x00000000, /* Address Translation Offset */ + 0x8000000000, /* Address Length */ + ,, PW64, AddressRangeMemory, TypeStatic) + }) + + Method(_CRS, 0) { + Return (CRES) + } +} diff --git a/arch/x86/cpu/qemu/dsdt.asl b/arch/x86/cpu/qemu/dsdt.asl new file mode 100644 index 0000000..95c9213 --- /dev/null +++ b/arch/x86/cpu/qemu/dsdt.asl @@ -0,0 +1,414 @@ +/* + * QEMU ACPI DSDT ASL definition + * + * Copyright (c) 2006 Fabrice Bellard + * + * Copyright (c) 2010 Isaku Yamahata + * yamahata at valinux co jp + * Based on acpi-dsdt.dsl, but heavily modified for q35 chipset. + */ + +DefinitionBlock ( + "dsdt.aml", // Output Filename + "DSDT", // Signature + 0x01, // DSDT Compliance Revision + "UBOO", // OEMID + "UBOOT ", // TABLE ID + 0x2 // OEM Revision + ) +{ + +#include "acpi/dbug.asl" + + Scope(_SB) { + OperationRegion(PCST, SystemIO, 0xae00, 0x0c) + OperationRegion(PCSB, SystemIO, 0xae0c, 0x01) + Field(PCSB, AnyAcc, NoLock, WriteAsZeros) { + PCIB, 8, + } + } + + +/**************************************************************** + * PCI Bus definition + ****************************************************************/ + + Scope(_SB) { + Device(PCI0) { + Name(_HID, EisaId("PNP0A08")) + Name(_CID, EisaId("PNP0A03")) + Name(_ADR, 0x00) + Name(_UID, 1) + + /* _OSC: based on sample of ACPI3.0b spec */ + Name(SUPP, 0) /* PCI _OSC Support Field value */ + Name(CTRL, 0) /* PCI _OSC Control Field value */ + Method(_OSC, 4) { + /* Create DWORD-addressable fields from Capabilities Buffer */ + CreateDWordField(Arg3, 0, CDW1) + + // Check for proper UUID + If (LEqual(Arg0, ToUUID("33DB4D5B-1FF7-401C-9657-7441C03DD766"))) + { + /* Create DWORD-addressable fields from Capabilities Buffer */ + CreateDWordField(Arg3, 4, CDW2) + CreateDWordField(Arg3, 8, CDW3) + + /* Save Capabilities DWORD2 & 3 */ + Store(CDW2, SUPP) + Store(CDW3, CTRL) + + /* Always allow native PME, AER (no dependencies) + Never allow SHPC (no SHPC controller in this system) */ + And(CTRL, 0x1d, CTRL) + + If (LNotEqual(Arg1, One)) { + /* Unknown revision */ + Or(CDW1, 0x08, CDW1) + } + If (LNotEqual(CDW3, CTRL)) { + /* Capabilities bits were masked */ + Or(CDW1, 0x10, CDW1) + } + /* Update DWORD3 in the buffer */ + Store(CTRL, CDW3) + } Else { + Or(CDW1, 4, CDW1) /* Unrecognized UUID */ + } + Return (Arg3) + } + } + } + +#include "acpi/pci-crs.asl" +#include "acpi/hpet.asl" + + +/**************************************************************** + * VGA + ****************************************************************/ + + Scope(_SB.PCI0) { + Device(VGA) { + Name(_ADR, 0x00010000) + Method(_S1D, 0, NotSerialized) { + Return (0x00) + } + Method(_S2D, 0, NotSerialized) { + Return (0x00) + } + Method(_S3D, 0, NotSerialized) { + Return (0x00) + } + } + } + + +/**************************************************************** + * LPC ISA bridge + ****************************************************************/ + + Scope(_SB.PCI0) { + /* PCI D31:f0 LPC ISA bridge */ + Device(ISA) { + /* PCI D31:f0 */ + Name(_ADR, 0x001f0000) + + /* ICH9 PCI to ISA irq remapping */ + OperationRegion(PIRQ, PCI_Config, 0x60, 0x0c) + + OperationRegion(LPCD, PCI_Config, 0x80, 0x2) + Field(LPCD, AnyAcc, NoLock, Preserve) { + COMA, 3, + , 1, + COMB, 3, + + Offset(0x01), + LPTD, 2, + , 2, + FDCD, 2 + } + OperationRegion(LPCE, PCI_Config, 0x82, 0x2) + Field(LPCE, AnyAcc, NoLock, Preserve) { + CAEN, 1, + CBEN, 1, + LPEN, 1, + FDEN, 1 + } + } + } + +#include "acpi/isa.asl" + + +/**************************************************************** + * PCI IRQs + ****************************************************************/ + + /* Zero => PIC mode, One => APIC Mode */ + Name(\PICF, Zero) + Method(_PIC, 1, NotSerialized) { + Store(Arg0, \PICF) + } + + Scope(_SB) { + Scope(PCI0) { +#define prt_slot_lnk(nr, lnk0, lnk1, lnk2, lnk3) \ + Package() { nr##ffff, 0, lnk0, 0 }, \ + Package() { nr##ffff, 1, lnk1, 0 }, \ + Package() { nr##ffff, 2, lnk2, 0 }, \ + Package() { nr##ffff, 3, lnk3, 0 } + +#define prt_slot_lnkA(nr) prt_slot_lnk(nr, LNKA, LNKB, LNKC, LNKD) +#define prt_slot_lnkB(nr) prt_slot_lnk(nr, LNKB, LNKC, LNKD, LNKA) +#define prt_slot_lnkC(nr) prt_slot_lnk(nr, LNKC, LNKD, LNKA, LNKB) +#define prt_slot_lnkD(nr) prt_slot_lnk(nr, LNKD, LNKA, LNKB, LNKC) + +#define prt_slot_lnkE(nr) prt_slot_lnk(nr, LNKE, LNKF, LNKG, LNKH) +#define prt_slot_lnkF(nr) prt_slot_lnk(nr, LNKF, LNKG, LNKH, LNKE) +#define prt_slot_lnkG(nr) prt_slot_lnk(nr, LNKG, LNKH, LNKE, LNKF) +#define prt_slot_lnkH(nr) prt_slot_lnk(nr, LNKH, LNKE, LNKF, LNKG) + + Name(PRTP, Package() { + prt_slot_lnkE(0x0000), + prt_slot_lnkF(0x0001), + prt_slot_lnkG(0x0002), + prt_slot_lnkH(0x0003), + prt_slot_lnkE(0x0004), + prt_slot_lnkF(0x0005), + prt_slot_lnkG(0x0006), + prt_slot_lnkH(0x0007), + prt_slot_lnkE(0x0008), + prt_slot_lnkF(0x0009), + prt_slot_lnkG(0x000a), + prt_slot_lnkH(0x000b), + prt_slot_lnkE(0x000c), + prt_slot_lnkF(0x000d), + prt_slot_lnkG(0x000e), + prt_slot_lnkH(0x000f), + prt_slot_lnkE(0x0010), + prt_slot_lnkF(0x0011), + prt_slot_lnkG(0x0012), + prt_slot_lnkH(0x0013), + prt_slot_lnkE(0x0014), + prt_slot_lnkF(0x0015), + prt_slot_lnkG(0x0016), + prt_slot_lnkH(0x0017), + prt_slot_lnkE(0x0018), + + /* INTA -> PIRQA for slot 25 - 31 + see the default value of D<N>IR */ + prt_slot_lnkA(0x0019), + prt_slot_lnkA(0x001a), + prt_slot_lnkA(0x001b), + prt_slot_lnkA(0x001c), + prt_slot_lnkA(0x001d), + + /* PCIe->PCI bridge. use PIRQ[E-H] */ + prt_slot_lnkE(0x001e), + + prt_slot_lnkA(0x001f) + }) + +#define prt_slot_gsi(nr, gsi0, gsi1, gsi2, gsi3) \ + Package() { nr##ffff, 0, gsi0, 0 }, \ + Package() { nr##ffff, 1, gsi1, 0 }, \ + Package() { nr##ffff, 2, gsi2, 0 }, \ + Package() { nr##ffff, 3, gsi3, 0 } + +#define prt_slot_gsiA(nr) prt_slot_gsi(nr, GSIA, GSIB, GSIC, GSID) +#define prt_slot_gsiB(nr) prt_slot_gsi(nr, GSIB, GSIC, GSID, GSIA) +#define prt_slot_gsiC(nr) prt_slot_gsi(nr, GSIC, GSID, GSIA, GSIB) +#define prt_slot_gsiD(nr) prt_slot_gsi(nr, GSID, GSIA, GSIB, GSIC) + +#define prt_slot_gsiE(nr) prt_slot_gsi(nr, GSIE, GSIF, GSIG, GSIH) +#define prt_slot_gsiF(nr) prt_slot_gsi(nr, GSIF, GSIG, GSIH, GSIE) +#define prt_slot_gsiG(nr) prt_slot_gsi(nr, GSIG, GSIH, GSIE, GSIF) +#define prt_slot_gsiH(nr) prt_slot_gsi(nr, GSIH, GSIE, GSIF, GSIG) + + Name(PRTA, Package() { + prt_slot_gsiE(0x0000), + prt_slot_gsiF(0x0001), + prt_slot_gsiG(0x0002), + prt_slot_gsiH(0x0003), + prt_slot_gsiE(0x0004), + prt_slot_gsiF(0x0005), + prt_slot_gsiG(0x0006), + prt_slot_gsiH(0x0007), + prt_slot_gsiE(0x0008), + prt_slot_gsiF(0x0009), + prt_slot_gsiG(0x000a), + prt_slot_gsiH(0x000b), + prt_slot_gsiE(0x000c), + prt_slot_gsiF(0x000d), + prt_slot_gsiG(0x000e), + prt_slot_gsiH(0x000f), + prt_slot_gsiE(0x0010), + prt_slot_gsiF(0x0011), + prt_slot_gsiG(0x0012), + prt_slot_gsiH(0x0013), + prt_slot_gsiE(0x0014), + prt_slot_gsiF(0x0015), + prt_slot_gsiG(0x0016), + prt_slot_gsiH(0x0017), + prt_slot_gsiE(0x0018), + + /* INTA -> PIRQA for slot 25 - 31, but 30 + see the default value of D<N>IR */ + prt_slot_gsiA(0x0019), + prt_slot_gsiA(0x001a), + prt_slot_gsiA(0x001b), + prt_slot_gsiA(0x001c), + prt_slot_gsiA(0x001d), + + /* PCIe->PCI bridge. use PIRQ[E-H] */ + prt_slot_gsiE(0x001e), + + prt_slot_gsiA(0x001f) + }) + + Method(_PRT, 0, NotSerialized) { + /* PCI IRQ routing table, example from ACPI 2.0a specification, + section 6.2.8.1 */ + /* Note: we provide the same info as the PCI routing + table of the Bochs BIOS */ + If (LEqual(\PICF, Zero)) { + Return (PRTP) + } Else { + Return (PRTA) + } + } + } + + Field(PCI0.ISA.PIRQ, ByteAcc, NoLock, Preserve) { + PRQA, 8, + PRQB, 8, + PRQC, 8, + PRQD, 8, + + Offset(0x08), + PRQE, 8, + PRQF, 8, + PRQG, 8, + PRQH, 8 + } + + Method(IQST, 1, NotSerialized) { + /* _STA method - get status */ + If (And(0x80, Arg0)) { + Return (0x09) + } + Return (0x0b) + } + Method(IQCR, 1, NotSerialized) { + /* _CRS method - get current settings */ + Name(PRR0, ResourceTemplate() { + Interrupt(, Level, ActiveHigh, Shared) { 0 } + }) + CreateDWordField(PRR0, 0x05, PRRI) + Store(And(Arg0, 0x0f), PRRI) + Return (PRR0) + } + +#define define_link(link, uid, reg) \ + Device(link) { \ + Name(_HID, EISAID("PNP0C0F")) \ + Name(_UID, uid) \ + Name(_PRS, ResourceTemplate() { \ + Interrupt(, Level, ActiveHigh, Shared) { \ + 5, 10, 11 \ + } \ + }) \ + Method(_STA, 0, NotSerialized) { \ + Return (IQST(reg)) \ + } \ + Method(_DIS, 0, NotSerialized) { \ + Or(reg, 0x80, reg) \ + } \ + Method(_CRS, 0, NotSerialized) { \ + Return (IQCR(reg)) \ + } \ + Method(_SRS, 1, NotSerialized) { \ + CreateDWordField(Arg0, 0x05, PRRI) \ + Store(PRRI, reg) \ + } \ + } + + define_link(LNKA, 0, PRQA) + define_link(LNKB, 1, PRQB) + define_link(LNKC, 2, PRQC) + define_link(LNKD, 3, PRQD) + define_link(LNKE, 4, PRQE) + define_link(LNKF, 5, PRQF) + define_link(LNKG, 6, PRQG) + define_link(LNKH, 7, PRQH) + +#define define_gsi_link(link, uid, gsi) \ + Device(link) { \ + Name(_HID, EISAID("PNP0C0F")) \ + Name(_UID, uid) \ + Name(_PRS, ResourceTemplate() { \ + Interrupt(, Level, ActiveHigh, Shared) { \ + gsi \ + } \ + }) \ + Name(_CRS, ResourceTemplate() { \ + Interrupt(, Level, ActiveHigh, Shared) { \ + gsi \ + } \ + }) \ + Method(_SRS, 1, NotSerialized) { \ + } \ + } + + define_gsi_link(GSIA, 0, 0x10) + define_gsi_link(GSIB, 0, 0x11) + define_gsi_link(GSIC, 0, 0x12) + define_gsi_link(GSID, 0, 0x13) + define_gsi_link(GSIE, 0, 0x14) + define_gsi_link(GSIF, 0, 0x15) + define_gsi_link(GSIG, 0, 0x16) + define_gsi_link(GSIH, 0, 0x17) + } + +/**************************************************************** + * General purpose events + ****************************************************************/ + + Scope(_GPE) { + Name(_HID, "ACPI0006") + + Method(_L00) { + } + Method(_L01) { + } + Method(_L02) { + } + Method(_L03) { + } + Method(_L04) { + } + Method(_L05) { + } + Method(_L06) { + } + Method(_L07) { + } + Method(_L08) { + } + Method(_L09) { + } + Method(_L0A) { + } + Method(_L0B) { + } + Method(_L0C) { + } + Method(_L0D) { + } + Method(_L0E) { + } + Method(_L0F) { + } + } +}

Hi Saket,
On Tue, Aug 18, 2015 at 3:29 AM, Saket Sinha saket.sinha89@gmail.com wrote:
The DSDT table contains a bytecode that is executed by a driver in the kernel.
Signed-off-by: Saket Sinha saket.sinha89@gmail.com
arch/x86/cpu/qemu/Makefile | 2 +- arch/x86/cpu/qemu/acpi/cpu-hotplug.asl | 78 +++++++ arch/x86/cpu/qemu/acpi/dbug.asl | 26 +++ arch/x86/cpu/qemu/acpi/hpet.asl | 33 +++ arch/x86/cpu/qemu/acpi/isa.asl | 102 ++++++++ arch/x86/cpu/qemu/acpi/pci-crs.asl | 61 +++++ arch/x86/cpu/qemu/dsdt.asl | 414 +++++++++++++++++++++++++++++++++ 7 files changed, 715 insertions(+), 1 deletion(-) create mode 100644 arch/x86/cpu/qemu/acpi/cpu-hotplug.asl create mode 100644 arch/x86/cpu/qemu/acpi/dbug.asl create mode 100644 arch/x86/cpu/qemu/acpi/hpet.asl create mode 100644 arch/x86/cpu/qemu/acpi/isa.asl create mode 100644 arch/x86/cpu/qemu/acpi/pci-crs.asl create mode 100644 arch/x86/cpu/qemu/dsdt.asl
diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile index 8c3884c..1c00d1d 100644 --- a/arch/x86/cpu/qemu/Makefile +++ b/arch/x86/cpu/qemu/Makefile @@ -8,5 +8,5 @@ ifndef CONFIG_EFI_STUB obj-y += car.o dram.o endif obj-y += qemu.o -obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.o +obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.o dsdt.o obj-$(CONFIG_PCI) += pci.o diff --git a/arch/x86/cpu/qemu/acpi/cpu-hotplug.asl b/arch/x86/cpu/qemu/acpi/cpu-hotplug.asl new file mode 100644 index 0000000..15b40a4 --- /dev/null +++ b/arch/x86/cpu/qemu/acpi/cpu-hotplug.asl @@ -0,0 +1,78 @@ +/****************************************************************
- CPU hotplug
- ****************************************************************/
/* CPU hotplug */
+Scope(_SB) {
- /* Objects filled in by run-time generated SSDT */
- External(NTFY, MethodObj)
- External(CPON, PkgObj)
- /* Methods called by run-time generated SSDT Processor objects */
- Method(CPMA, 1, NotSerialized) {
/* _MAT method - create an madt apic buffer
Arg0 = Processor ID = Local APIC ID
Local0 = CPON flag for this cpu */
Please use correct multi-line comment format.
Store(DerefOf(Index(CPON, Arg0)), Local0)
/* Local1 = Buffer (in madt apic form) to return */
Store(Buffer(8) {0x00, 0x08, 0x00, 0x00, 0x00, 0, 0, 0}, Local1)
/* Update the processor id, lapic id, and enable/disable status */
Store(Arg0, Index(Local1, 2))
Store(Arg0, Index(Local1, 3))
Store(Local0, Index(Local1, 4))
Return (Local1)
- }
- Method(CPST, 1, NotSerialized) {
/* _STA method - return ON status of cpu
Arg0 = Processor ID = Local APIC ID
Local0 = CPON flag for this cpu */
ditto.
Store(DerefOf(Index(CPON, Arg0)), Local0)
If (Local0) {
Return (0xf)
} Else {
Return (0x0)
}
- }
- Method(CPEJ, 2, NotSerialized) {
/* _EJ0 method - eject callback */
Sleep(200)
- }
- /* CPU hotplug notify method */
- OperationRegion(PRST, SystemIO, 0xaf00, 32)
- Field(PRST, ByteAcc, NoLock, Preserve) {
PRS, 256
- }
- Method(PRSC, 0) {
/* Local5 = active cpu bitmap */
Store(PRS, Local5)
/* Local2 = last read byte from bitmap */
Store(Zero, Local2)
/* Local0 = Processor ID / APIC ID iterator */
Store(Zero, Local0)
While (LLess(Local0, SizeOf(CPON))) {
/* Local1 = CPON flag for this cpu */
Store(DerefOf(Index(CPON, Local0)), Local1)
If (And(Local0, 0x07)) {
/* Shift down previously read bitmap byte */
ShiftRight(Local2, 1, Local2)
} Else {
/* Read next byte from cpu bitmap */
Store(DerefOf(Index(Local5, ShiftRight(Local0, 3))), Local2)
}
/* Local3 = active state for this cpu */
Store(And(Local2, 1), Local3)
If (LNotEqual(Local1, Local3)) {
/* State change - update CPON with new state */
Store(Local3, Index(CPON, Local0))
/* Do CPU notify */
If (LEqual(Local3, 1)) {
NTFY(Local0, 1)
} Else {
NTFY(Local0, 3)
}
}
Increment(Local0)
}
- }
+} diff --git a/arch/x86/cpu/qemu/acpi/dbug.asl b/arch/x86/cpu/qemu/acpi/dbug.asl new file mode 100644 index 0000000..55c932a --- /dev/null +++ b/arch/x86/cpu/qemu/acpi/dbug.asl @@ -0,0 +1,26 @@ +/****************************************************************
- Debugging
- ****************************************************************/
/* Debugging */
+Scope() {
- /* Debug Output */
- OperationRegion(DBG, SystemIO, 0x0402, 0x01)
- Field(DBG, ByteAcc, NoLock, Preserve) {
DBGB, 8,
- }
- /* Debug method - use this method to send output to the QEMU
* BIOS debug port. This method handles strings, integers,
* and buffers. For example: DBUG("abc") DBUG(0x123) */
Please use correct multi-line comment format.
- Method(DBUG, 1) {
ToHexString(Arg0, Local0)
ToBuffer(Local0, Local0)
Subtract(SizeOf(Local0), 1, Local1)
Store(Zero, Local2)
While (LLess(Local2, Local1)) {
Store(DerefOf(Index(Local0, Local2)), DBGB)
Increment(Local2)
}
Store(0x0a, dbgb)
- }
+} diff --git a/arch/x86/cpu/qemu/acpi/hpet.asl b/arch/x86/cpu/qemu/acpi/hpet.asl new file mode 100644 index 0000000..4251580 --- /dev/null +++ b/arch/x86/cpu/qemu/acpi/hpet.asl @@ -0,0 +1,33 @@ +/****************************************************************
- HPET
- ****************************************************************/
/* HPET */
+Scope(_SB) {
- Device(HPET) {
Name(_HID, EISAID("PNP0103"))
Name(_UID, 0)
OperationRegion(HPTM, SystemMemory, 0xfed00000, 0x400)
Field(HPTM, DWordAcc, Lock, Preserve) {
VEND, 32,
PRD, 32,
}
Method(_STA, 0, NotSerialized) {
Store(VEND, Local0)
Store(PRD, Local1)
ShiftRight(Local0, 16, Local0)
If (LOr(LEqual(Local0, 0), LEqual(Local0, 0xffff))) {
Return (0x0)
}
If (LOr(LEqual(Local1, 0), LGreater(Local1, 100000000))) {
Return (0x0)
}
Return (0x0f)
}
Name(_CRS, ResourceTemplate() {
Memory32Fixed(ReadOnly,
0xfed00000, /* Address Base */
0x00000400, /* Address Length */
)
})
- }
+} diff --git a/arch/x86/cpu/qemu/acpi/isa.asl b/arch/x86/cpu/qemu/acpi/isa.asl new file mode 100644 index 0000000..d6b3d9b --- /dev/null +++ b/arch/x86/cpu/qemu/acpi/isa.asl @@ -0,0 +1,102 @@ +/* Common legacy ISA style devices. */ +Scope(_SB.PCI0.ISA) {
- Device(RTC) {
Name(_HID, EisaId("PNP0B00"))
Name(_CRS, ResourceTemplate() {
IO(Decode16, 0x0070, 0x0070, 0x10, 0x02)
IRQNoFlags() { 8 }
IO(Decode16, 0x0072, 0x0072, 0x02, 0x06)
})
- }
- Device(KBD) {
Name(_HID, EisaId("PNP0303"))
Method(_STA, 0, NotSerialized) {
Return (0x0f)
}
Name(_CRS, ResourceTemplate() {
IO(Decode16, 0x0060, 0x0060, 0x01, 0x01)
IO(Decode16, 0x0064, 0x0064, 0x01, 0x01)
IRQNoFlags() { 1 }
})
- }
- Device(MOU) {
Name(_HID, EisaId("PNP0F13"))
Method(_STA, 0, NotSerialized) {
Return (0x0f)
}
Name(_CRS, ResourceTemplate() {
IRQNoFlags() { 12 }
})
- }
- Device(FDC0) {
Name(_HID, EisaId("PNP0700"))
Method(_STA, 0, NotSerialized) {
Store(FDEN, Local0)
If (LEqual(Local0, 0)) {
Return (0x00)
} Else {
Return (0x0f)
}
}
Name(_CRS, ResourceTemplate() {
IO(Decode16, 0x03f2, 0x03f2, 0x00, 0x04)
IO(Decode16, 0x03f7, 0x03f7, 0x00, 0x01)
IRQNoFlags() { 6 }
DMA(Compatibility, NotBusMaster, Transfer8) { 2 }
})
- }
- Device(LPT) {
Name(_HID, EisaId("PNP0400"))
Method(_STA, 0, NotSerialized) {
Store(LPEN, Local0)
If (LEqual(Local0, 0)) {
Return (0x00)
} Else {
Return (0x0f)
}
}
Name(_CRS, ResourceTemplate() {
IO(Decode16, 0x0378, 0x0378, 0x08, 0x08)
IRQNoFlags() { 7 }
})
- }
- Device(COM1) {
Name(_HID, EisaId("PNP0501"))
Name(_UID, 0x01)
Method(_STA, 0, NotSerialized) {
Store(CAEN, Local0)
If (LEqual(Local0, 0)) {
Return (0x00)
} Else {
Return (0x0f)
}
}
Name(_CRS, ResourceTemplate() {
IO(Decode16, 0x03f8, 0x03f8, 0x00, 0x08)
IRQNoFlags() { 4 }
})
- }
- Device(COM2) {
Name(_HID, EisaId("PNP0501"))
Name(_UID, 0x02)
Method(_STA, 0, NotSerialized) {
Store(CBEN, Local0)
If (LEqual(Local0, 0)) {
Return (0x00)
} Else {
Return (0x0f)
}
}
Name(_CRS, ResourceTemplate() {
IO(Decode16, 0x02f8, 0x02f8, 0x00, 0x08)
IRQNoFlags() { 3 }
})
- }
+} diff --git a/arch/x86/cpu/qemu/acpi/pci-crs.asl b/arch/x86/cpu/qemu/acpi/pci-crs.asl new file mode 100644 index 0000000..43b2858 --- /dev/null +++ b/arch/x86/cpu/qemu/acpi/pci-crs.asl @@ -0,0 +1,61 @@ +/* PCI CRS (current resources) definition. */ +Scope(_SB.PCI0) {
- Name(CRES, ResourceTemplate() {
WordBusNumber(ResourceProducer, MinFixed, MaxFixed, PosDecode,
0x0000, /* Address Space Granularity */
0x0000, /* Address Range Minimum */
0x00ff, /* Address Range Maximum */
0x0000, /* Address Translation Offset */
0x0100, /* Address Length */
,, )
IO(Decode16,
0x0cf8, /* Address Range Minimum */
0x0cf8, /* Address Range Maximum */
0x01, /* Address Alignment */
0x08, /* Address Length */
)
WordIO(ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
0x0000, /* Address Space Granularity */
0x0000, /* Address Range Minimum */
0x0cf7, /* Address Range Maximum */
0x0000, /* Address Translation Offset */
0x0cf8, /* Address Length */
,, , TypeStatic)
WordIO(ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
0x0000, /* Address Space Granularity */
0x0d00, /* Address Range Minimum */
0xffff, /* Address Range Maximum */
0x0000, /* Address Translation Offset */
0xf300, /* Address Length */
,, , TypeStatic)
DWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
0x00000000, /* Address Space Granularity */
0x000a0000, /* Address Range Minimum */
0x000bffff, /* Address Range Maximum */
0x00000000, /* Address Translation Offset */
0x00020000, /* Address Length */
,, , AddressRangeMemory, TypeStatic)
DWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
0x00000000, /* Address Space Granularity */
0xe0000000, /* Address Range Minimum */
0xfebfffff, /* Address Range Maximum */
0x00000000, /* Address Translation Offset */
0x1ec00000, /* Address Length */
,, PW32, AddressRangeMemory, TypeStatic)
- })
- Name(CR64, ResourceTemplate() {
QWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
0x00000000, /* Address Space Granularity */
0x8000000000, /* Address Range Minimum */
0xffffffff, /* Address Range Maximum */
0x00000000, /* Address Translation Offset */
0x8000000000, /* Address Length */
,, PW64, AddressRangeMemory, TypeStatic)
- })
- Method(_CRS, 0) {
Return (CRES)
- }
+} diff --git a/arch/x86/cpu/qemu/dsdt.asl b/arch/x86/cpu/qemu/dsdt.asl new file mode 100644 index 0000000..95c9213 --- /dev/null +++ b/arch/x86/cpu/qemu/dsdt.asl @@ -0,0 +1,414 @@ +/*
- QEMU ACPI DSDT ASL definition
- Copyright (c) 2006 Fabrice Bellard
- Copyright (c) 2010 Isaku Yamahata
yamahata at valinux co jp
- Based on acpi-dsdt.dsl, but heavily modified for q35 chipset.
- */
+DefinitionBlock (
- "dsdt.aml", // Output Filename
- "DSDT", // Signature
- 0x01, // DSDT Compliance Revision
- "UBOO", // OEMID
- "UBOOT ", // TABLE ID
- 0x2 // OEM Revision
Please use C-style comment format.
- )
+{
+#include "acpi/dbug.asl"
- Scope(_SB) {
OperationRegion(PCST, SystemIO, 0xae00, 0x0c)
OperationRegion(PCSB, SystemIO, 0xae0c, 0x01)
Field(PCSB, AnyAcc, NoLock, WriteAsZeros) {
PCIB, 8,
}
- }
+/****************************************************************
- PCI Bus definition
- ****************************************************************/
/* PCI Bus definition */
- Scope(_SB) {
Device(PCI0) {
Name(_HID, EisaId("PNP0A08"))
Name(_CID, EisaId("PNP0A03"))
Name(_ADR, 0x00)
Name(_UID, 1)
/* _OSC: based on sample of ACPI3.0b spec */
Name(SUPP, 0) /* PCI _OSC Support Field value */
Name(CTRL, 0) /* PCI _OSC Control Field value */
Method(_OSC, 4) {
/* Create DWORD-addressable fields from Capabilities Buffer */
CreateDWordField(Arg3, 0, CDW1)
// Check for proper UUID
Please use C-style comment format.
If (LEqual(Arg0, ToUUID("33DB4D5B-1FF7-401C-9657-7441C03DD766")))
{
/* Create DWORD-addressable fields from Capabilities Buffer */
Nits: indention is not correct
CreateDWordField(Arg3, 4, CDW2)
CreateDWordField(Arg3, 8, CDW3)
/* Save Capabilities DWORD2 & 3 */
Store(CDW2, SUPP)
Store(CDW3, CTRL)
/* Always allow native PME, AER (no dependencies)
Never allow SHPC (no SHPC controller in this system) */
Please use correct multi-line comment.
And(CTRL, 0x1d, CTRL)
If (LNotEqual(Arg1, One)) {
/* Unknown revision */
Or(CDW1, 0x08, CDW1)
}
If (LNotEqual(CDW3, CTRL)) {
/* Capabilities bits were masked */
Or(CDW1, 0x10, CDW1)
}
/* Update DWORD3 in the buffer */
Store(CTRL, CDW3)
} Else {
Or(CDW1, 4, CDW1) /* Unrecognized UUID */
}
Return (Arg3)
}
}
- }
+#include "acpi/pci-crs.asl" +#include "acpi/hpet.asl"
+/****************************************************************
- VGA
- ****************************************************************/
/* VGA */
- Scope(_SB.PCI0) {
Device(VGA) {
Name(_ADR, 0x00010000)
Method(_S1D, 0, NotSerialized) {
Return (0x00)
}
Method(_S2D, 0, NotSerialized) {
Return (0x00)
}
Method(_S3D, 0, NotSerialized) {
Return (0x00)
}
}
- }
+/****************************************************************
- LPC ISA bridge
- ****************************************************************/
/* LPC ISA bridge */
- Scope(_SB.PCI0) {
/* PCI D31:f0 LPC ISA bridge */
Device(ISA) {
/* PCI D31:f0 */
Name(_ADR, 0x001f0000)
/* ICH9 PCI to ISA irq remapping */
OperationRegion(PIRQ, PCI_Config, 0x60, 0x0c)
OperationRegion(LPCD, PCI_Config, 0x80, 0x2)
Field(LPCD, AnyAcc, NoLock, Preserve) {
COMA, 3,
, 1,
COMB, 3,
Offset(0x01),
LPTD, 2,
, 2,
FDCD, 2
}
OperationRegion(LPCE, PCI_Config, 0x82, 0x2)
Field(LPCE, AnyAcc, NoLock, Preserve) {
CAEN, 1,
CBEN, 1,
LPEN, 1,
FDEN, 1
}
}
- }
+#include "acpi/isa.asl"
+/****************************************************************
- PCI IRQs
- ****************************************************************/
/* PCI IRQs */
- /* Zero => PIC mode, One => APIC Mode */
- Name(\PICF, Zero)
- Method(_PIC, 1, NotSerialized) {
Store(Arg0, \PICF)
- }
- Scope(_SB) {
Scope(PCI0) {
+#define prt_slot_lnk(nr, lnk0, lnk1, lnk2, lnk3) \
- Package() { nr##ffff, 0, lnk0, 0 }, \
- Package() { nr##ffff, 1, lnk1, 0 }, \
- Package() { nr##ffff, 2, lnk2, 0 }, \
- Package() { nr##ffff, 3, lnk3, 0 }
+#define prt_slot_lnkA(nr) prt_slot_lnk(nr, LNKA, LNKB, LNKC, LNKD) +#define prt_slot_lnkB(nr) prt_slot_lnk(nr, LNKB, LNKC, LNKD, LNKA) +#define prt_slot_lnkC(nr) prt_slot_lnk(nr, LNKC, LNKD, LNKA, LNKB) +#define prt_slot_lnkD(nr) prt_slot_lnk(nr, LNKD, LNKA, LNKB, LNKC)
+#define prt_slot_lnkE(nr) prt_slot_lnk(nr, LNKE, LNKF, LNKG, LNKH) +#define prt_slot_lnkF(nr) prt_slot_lnk(nr, LNKF, LNKG, LNKH, LNKE) +#define prt_slot_lnkG(nr) prt_slot_lnk(nr, LNKG, LNKH, LNKE, LNKF) +#define prt_slot_lnkH(nr) prt_slot_lnk(nr, LNKH, LNKE, LNKF, LNKG)
Name(PRTP, Package() {
prt_slot_lnkE(0x0000),
prt_slot_lnkF(0x0001),
prt_slot_lnkG(0x0002),
prt_slot_lnkH(0x0003),
prt_slot_lnkE(0x0004),
prt_slot_lnkF(0x0005),
prt_slot_lnkG(0x0006),
prt_slot_lnkH(0x0007),
prt_slot_lnkE(0x0008),
prt_slot_lnkF(0x0009),
prt_slot_lnkG(0x000a),
prt_slot_lnkH(0x000b),
prt_slot_lnkE(0x000c),
prt_slot_lnkF(0x000d),
prt_slot_lnkG(0x000e),
prt_slot_lnkH(0x000f),
prt_slot_lnkE(0x0010),
prt_slot_lnkF(0x0011),
prt_slot_lnkG(0x0012),
prt_slot_lnkH(0x0013),
prt_slot_lnkE(0x0014),
prt_slot_lnkF(0x0015),
prt_slot_lnkG(0x0016),
prt_slot_lnkH(0x0017),
prt_slot_lnkE(0x0018),
/* INTA -> PIRQA for slot 25 - 31
see the default value of D<N>IR */
prt_slot_lnkA(0x0019),
prt_slot_lnkA(0x001a),
prt_slot_lnkA(0x001b),
prt_slot_lnkA(0x001c),
prt_slot_lnkA(0x001d),
/* PCIe->PCI bridge. use PIRQ[E-H] */
prt_slot_lnkE(0x001e),
prt_slot_lnkA(0x001f)
})
+#define prt_slot_gsi(nr, gsi0, gsi1, gsi2, gsi3) \
- Package() { nr##ffff, 0, gsi0, 0 }, \
- Package() { nr##ffff, 1, gsi1, 0 }, \
- Package() { nr##ffff, 2, gsi2, 0 }, \
- Package() { nr##ffff, 3, gsi3, 0 }
+#define prt_slot_gsiA(nr) prt_slot_gsi(nr, GSIA, GSIB, GSIC, GSID) +#define prt_slot_gsiB(nr) prt_slot_gsi(nr, GSIB, GSIC, GSID, GSIA) +#define prt_slot_gsiC(nr) prt_slot_gsi(nr, GSIC, GSID, GSIA, GSIB) +#define prt_slot_gsiD(nr) prt_slot_gsi(nr, GSID, GSIA, GSIB, GSIC)
+#define prt_slot_gsiE(nr) prt_slot_gsi(nr, GSIE, GSIF, GSIG, GSIH) +#define prt_slot_gsiF(nr) prt_slot_gsi(nr, GSIF, GSIG, GSIH, GSIE) +#define prt_slot_gsiG(nr) prt_slot_gsi(nr, GSIG, GSIH, GSIE, GSIF) +#define prt_slot_gsiH(nr) prt_slot_gsi(nr, GSIH, GSIE, GSIF, GSIG)
Name(PRTA, Package() {
prt_slot_gsiE(0x0000),
prt_slot_gsiF(0x0001),
prt_slot_gsiG(0x0002),
prt_slot_gsiH(0x0003),
prt_slot_gsiE(0x0004),
prt_slot_gsiF(0x0005),
prt_slot_gsiG(0x0006),
prt_slot_gsiH(0x0007),
prt_slot_gsiE(0x0008),
prt_slot_gsiF(0x0009),
prt_slot_gsiG(0x000a),
prt_slot_gsiH(0x000b),
prt_slot_gsiE(0x000c),
prt_slot_gsiF(0x000d),
prt_slot_gsiG(0x000e),
prt_slot_gsiH(0x000f),
prt_slot_gsiE(0x0010),
prt_slot_gsiF(0x0011),
prt_slot_gsiG(0x0012),
prt_slot_gsiH(0x0013),
prt_slot_gsiE(0x0014),
prt_slot_gsiF(0x0015),
prt_slot_gsiG(0x0016),
prt_slot_gsiH(0x0017),
prt_slot_gsiE(0x0018),
/* INTA -> PIRQA for slot 25 - 31, but 30
see the default value of D<N>IR */
Please use correct multi-line comment format.
prt_slot_gsiA(0x0019),
prt_slot_gsiA(0x001a),
prt_slot_gsiA(0x001b),
prt_slot_gsiA(0x001c),
prt_slot_gsiA(0x001d),
/* PCIe->PCI bridge. use PIRQ[E-H] */
prt_slot_gsiE(0x001e),
prt_slot_gsiA(0x001f)
})
Method(_PRT, 0, NotSerialized) {
/* PCI IRQ routing table, example from ACPI 2.0a specification,
section 6.2.8.1 */
ditto.
/* Note: we provide the same info as the PCI routing
table of the Bochs BIOS */
ditto.
If (LEqual(\PICF, Zero)) {
Return (PRTP)
} Else {
Return (PRTA)
}
}
}
Field(PCI0.ISA.PIRQ, ByteAcc, NoLock, Preserve) {
PRQA, 8,
PRQB, 8,
PRQC, 8,
PRQD, 8,
Offset(0x08),
PRQE, 8,
PRQF, 8,
PRQG, 8,
PRQH, 8
}
Method(IQST, 1, NotSerialized) {
/* _STA method - get status */
If (And(0x80, Arg0)) {
Return (0x09)
}
Return (0x0b)
}
Method(IQCR, 1, NotSerialized) {
/* _CRS method - get current settings */
Name(PRR0, ResourceTemplate() {
Interrupt(, Level, ActiveHigh, Shared) { 0 }
})
CreateDWordField(PRR0, 0x05, PRRI)
Store(And(Arg0, 0x0f), PRRI)
Return (PRR0)
}
+#define define_link(link, uid, reg) \
Device(link) { \
Name(_HID, EISAID("PNP0C0F")) \
Name(_UID, uid) \
Name(_PRS, ResourceTemplate() { \
Interrupt(, Level, ActiveHigh, Shared) { \
5, 10, 11 \
} \
}) \
Method(_STA, 0, NotSerialized) { \
Return (IQST(reg)) \
} \
Method(_DIS, 0, NotSerialized) { \
Or(reg, 0x80, reg) \
} \
Method(_CRS, 0, NotSerialized) { \
Return (IQCR(reg)) \
} \
Method(_SRS, 1, NotSerialized) { \
CreateDWordField(Arg0, 0x05, PRRI) \
Store(PRRI, reg) \
} \
}
define_link(LNKA, 0, PRQA)
define_link(LNKB, 1, PRQB)
define_link(LNKC, 2, PRQC)
define_link(LNKD, 3, PRQD)
define_link(LNKE, 4, PRQE)
define_link(LNKF, 5, PRQF)
define_link(LNKG, 6, PRQG)
define_link(LNKH, 7, PRQH)
+#define define_gsi_link(link, uid, gsi) \
Device(link) { \
Name(_HID, EISAID("PNP0C0F")) \
Name(_UID, uid) \
Name(_PRS, ResourceTemplate() { \
Interrupt(, Level, ActiveHigh, Shared) { \
gsi \
} \
}) \
Name(_CRS, ResourceTemplate() { \
Interrupt(, Level, ActiveHigh, Shared) { \
gsi \
} \
}) \
Method(_SRS, 1, NotSerialized) { \
} \
}
define_gsi_link(GSIA, 0, 0x10)
define_gsi_link(GSIB, 0, 0x11)
define_gsi_link(GSIC, 0, 0x12)
define_gsi_link(GSID, 0, 0x13)
define_gsi_link(GSIE, 0, 0x14)
define_gsi_link(GSIF, 0, 0x15)
define_gsi_link(GSIG, 0, 0x16)
define_gsi_link(GSIH, 0, 0x17)
- }
+/****************************************************************
- General purpose events
- ****************************************************************/
/* General purpose events */
- Scope(_GPE) {
Name(_HID, "ACPI0006")
Method(_L00) {
}
Method(_L01) {
}
Method(_L02) {
}
Method(_L03) {
}
Method(_L04) {
}
Method(_L05) {
}
Method(_L06) {
}
Method(_L07) {
}
Method(_L08) {
}
Method(_L09) {
}
Method(_L0A) {
}
Method(_L0B) {
}
Method(_L0C) {
}
Method(_L0D) {
}
Method(_L0E) {
}
Method(_L0F) {
}
- }
+}
Regards, Bin

Hi Bin,
Please find my response inline -
On Tue, Aug 18, 2015 at 12:36 PM, Bin Meng bmeng.cn@gmail.com wrote:
Hi Saket,
On Tue, Aug 18, 2015 at 3:29 AM, Saket Sinha saket.sinha89@gmail.com wrote:
The DSDT table contains a bytecode that is executed by a driver in the kernel.
Signed-off-by: Saket Sinha saket.sinha89@gmail.com
arch/x86/cpu/qemu/Makefile | 2 +- arch/x86/cpu/qemu/acpi/cpu-hotplug.asl | 78 +++++++ arch/x86/cpu/qemu/acpi/dbug.asl | 26 +++ arch/x86/cpu/qemu/acpi/hpet.asl | 33 +++ arch/x86/cpu/qemu/acpi/isa.asl | 102 ++++++++ arch/x86/cpu/qemu/acpi/pci-crs.asl | 61 +++++ arch/x86/cpu/qemu/dsdt.asl | 414 +++++++++++++++++++++++++++++++++ 7 files changed, 715 insertions(+), 1 deletion(-) create mode 100644 arch/x86/cpu/qemu/acpi/cpu-hotplug.asl create mode 100644 arch/x86/cpu/qemu/acpi/dbug.asl create mode 100644 arch/x86/cpu/qemu/acpi/hpet.asl create mode 100644 arch/x86/cpu/qemu/acpi/isa.asl create mode 100644 arch/x86/cpu/qemu/acpi/pci-crs.asl create mode 100644 arch/x86/cpu/qemu/dsdt.asl
diff --git a/arch/x86/cpu/qemu/Makefile b/arch/x86/cpu/qemu/Makefile index 8c3884c..1c00d1d 100644 --- a/arch/x86/cpu/qemu/Makefile +++ b/arch/x86/cpu/qemu/Makefile @@ -8,5 +8,5 @@ ifndef CONFIG_EFI_STUB obj-y += car.o dram.o endif obj-y += qemu.o -obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.o +obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.o dsdt.o obj-$(CONFIG_PCI) += pci.o diff --git a/arch/x86/cpu/qemu/acpi/cpu-hotplug.asl b/arch/x86/cpu/qemu/acpi/cpu-hotplug.asl new file mode 100644 index 0000000..15b40a4 --- /dev/null +++ b/arch/x86/cpu/qemu/acpi/cpu-hotplug.asl @@ -0,0 +1,78 @@ +/****************************************************************
- CPU hotplug
- ****************************************************************/
/* CPU hotplug */
Addressed in patchset series v6.
+Scope(_SB) {
- /* Objects filled in by run-time generated SSDT */
- External(NTFY, MethodObj)
- External(CPON, PkgObj)
- /* Methods called by run-time generated SSDT Processor objects */
- Method(CPMA, 1, NotSerialized) {
/* _MAT method - create an madt apic buffer
Arg0 = Processor ID = Local APIC ID
Local0 = CPON flag for this cpu */
Please use correct multi-line comment format.
Addressed in patchset series v6.
Store(DerefOf(Index(CPON, Arg0)), Local0)
/* Local1 = Buffer (in madt apic form) to return */
Store(Buffer(8) {0x00, 0x08, 0x00, 0x00, 0x00, 0, 0, 0}, Local1)
/* Update the processor id, lapic id, and enable/disable status */
Store(Arg0, Index(Local1, 2))
Store(Arg0, Index(Local1, 3))
Store(Local0, Index(Local1, 4))
Return (Local1)
- }
- Method(CPST, 1, NotSerialized) {
/* _STA method - return ON status of cpu
Arg0 = Processor ID = Local APIC ID
Local0 = CPON flag for this cpu */
ditto.
Addressed in patchset series v6.
Store(DerefOf(Index(CPON, Arg0)), Local0)
If (Local0) {
Return (0xf)
} Else {
Return (0x0)
}
- }
- Method(CPEJ, 2, NotSerialized) {
/* _EJ0 method - eject callback */
Sleep(200)
- }
- /* CPU hotplug notify method */
- OperationRegion(PRST, SystemIO, 0xaf00, 32)
- Field(PRST, ByteAcc, NoLock, Preserve) {
PRS, 256
- }
- Method(PRSC, 0) {
/* Local5 = active cpu bitmap */
Store(PRS, Local5)
/* Local2 = last read byte from bitmap */
Store(Zero, Local2)
/* Local0 = Processor ID / APIC ID iterator */
Store(Zero, Local0)
While (LLess(Local0, SizeOf(CPON))) {
/* Local1 = CPON flag for this cpu */
Store(DerefOf(Index(CPON, Local0)), Local1)
If (And(Local0, 0x07)) {
/* Shift down previously read bitmap byte */
ShiftRight(Local2, 1, Local2)
} Else {
/* Read next byte from cpu bitmap */
Store(DerefOf(Index(Local5, ShiftRight(Local0, 3))), Local2)
}
/* Local3 = active state for this cpu */
Store(And(Local2, 1), Local3)
If (LNotEqual(Local1, Local3)) {
/* State change - update CPON with new state */
Store(Local3, Index(CPON, Local0))
/* Do CPU notify */
If (LEqual(Local3, 1)) {
NTFY(Local0, 1)
} Else {
NTFY(Local0, 3)
}
}
Increment(Local0)
}
- }
+} diff --git a/arch/x86/cpu/qemu/acpi/dbug.asl b/arch/x86/cpu/qemu/acpi/dbug.asl new file mode 100644 index 0000000..55c932a --- /dev/null +++ b/arch/x86/cpu/qemu/acpi/dbug.asl @@ -0,0 +1,26 @@ +/****************************************************************
- Debugging
- ****************************************************************/
/* Debugging */
Addressed in patchset series v6.
+Scope() {
- /* Debug Output */
- OperationRegion(DBG, SystemIO, 0x0402, 0x01)
- Field(DBG, ByteAcc, NoLock, Preserve) {
DBGB, 8,
- }
- /* Debug method - use this method to send output to the QEMU
* BIOS debug port. This method handles strings, integers,
* and buffers. For example: DBUG("abc") DBUG(0x123) */
Please use correct multi-line comment format.
Addressed in patchset series v6.
- Method(DBUG, 1) {
ToHexString(Arg0, Local0)
ToBuffer(Local0, Local0)
Subtract(SizeOf(Local0), 1, Local1)
Store(Zero, Local2)
While (LLess(Local2, Local1)) {
Store(DerefOf(Index(Local0, Local2)), DBGB)
Increment(Local2)
}
Store(0x0a, dbgb)
- }
+} diff --git a/arch/x86/cpu/qemu/acpi/hpet.asl b/arch/x86/cpu/qemu/acpi/hpet.asl new file mode 100644 index 0000000..4251580 --- /dev/null +++ b/arch/x86/cpu/qemu/acpi/hpet.asl @@ -0,0 +1,33 @@ +/****************************************************************
- HPET
- ****************************************************************/
/* HPET */
Addressed in patchset series v6.
+Scope(_SB) {
- Device(HPET) {
Name(_HID, EISAID("PNP0103"))
Name(_UID, 0)
OperationRegion(HPTM, SystemMemory, 0xfed00000, 0x400)
Field(HPTM, DWordAcc, Lock, Preserve) {
VEND, 32,
PRD, 32,
}
Method(_STA, 0, NotSerialized) {
Store(VEND, Local0)
Store(PRD, Local1)
ShiftRight(Local0, 16, Local0)
If (LOr(LEqual(Local0, 0), LEqual(Local0, 0xffff))) {
Return (0x0)
}
If (LOr(LEqual(Local1, 0), LGreater(Local1, 100000000))) {
Return (0x0)
}
Return (0x0f)
}
Name(_CRS, ResourceTemplate() {
Memory32Fixed(ReadOnly,
0xfed00000, /* Address Base */
0x00000400, /* Address Length */
)
})
- }
+} diff --git a/arch/x86/cpu/qemu/acpi/isa.asl b/arch/x86/cpu/qemu/acpi/isa.asl new file mode 100644 index 0000000..d6b3d9b --- /dev/null +++ b/arch/x86/cpu/qemu/acpi/isa.asl @@ -0,0 +1,102 @@ +/* Common legacy ISA style devices. */ +Scope(_SB.PCI0.ISA) {
- Device(RTC) {
Name(_HID, EisaId("PNP0B00"))
Name(_CRS, ResourceTemplate() {
IO(Decode16, 0x0070, 0x0070, 0x10, 0x02)
IRQNoFlags() { 8 }
IO(Decode16, 0x0072, 0x0072, 0x02, 0x06)
})
- }
- Device(KBD) {
Name(_HID, EisaId("PNP0303"))
Method(_STA, 0, NotSerialized) {
Return (0x0f)
}
Name(_CRS, ResourceTemplate() {
IO(Decode16, 0x0060, 0x0060, 0x01, 0x01)
IO(Decode16, 0x0064, 0x0064, 0x01, 0x01)
IRQNoFlags() { 1 }
})
- }
- Device(MOU) {
Name(_HID, EisaId("PNP0F13"))
Method(_STA, 0, NotSerialized) {
Return (0x0f)
}
Name(_CRS, ResourceTemplate() {
IRQNoFlags() { 12 }
})
- }
- Device(FDC0) {
Name(_HID, EisaId("PNP0700"))
Method(_STA, 0, NotSerialized) {
Store(FDEN, Local0)
If (LEqual(Local0, 0)) {
Return (0x00)
} Else {
Return (0x0f)
}
}
Name(_CRS, ResourceTemplate() {
IO(Decode16, 0x03f2, 0x03f2, 0x00, 0x04)
IO(Decode16, 0x03f7, 0x03f7, 0x00, 0x01)
IRQNoFlags() { 6 }
DMA(Compatibility, NotBusMaster, Transfer8) { 2 }
})
- }
- Device(LPT) {
Name(_HID, EisaId("PNP0400"))
Method(_STA, 0, NotSerialized) {
Store(LPEN, Local0)
If (LEqual(Local0, 0)) {
Return (0x00)
} Else {
Return (0x0f)
}
}
Name(_CRS, ResourceTemplate() {
IO(Decode16, 0x0378, 0x0378, 0x08, 0x08)
IRQNoFlags() { 7 }
})
- }
- Device(COM1) {
Name(_HID, EisaId("PNP0501"))
Name(_UID, 0x01)
Method(_STA, 0, NotSerialized) {
Store(CAEN, Local0)
If (LEqual(Local0, 0)) {
Return (0x00)
} Else {
Return (0x0f)
}
}
Name(_CRS, ResourceTemplate() {
IO(Decode16, 0x03f8, 0x03f8, 0x00, 0x08)
IRQNoFlags() { 4 }
})
- }
- Device(COM2) {
Name(_HID, EisaId("PNP0501"))
Name(_UID, 0x02)
Method(_STA, 0, NotSerialized) {
Store(CBEN, Local0)
If (LEqual(Local0, 0)) {
Return (0x00)
} Else {
Return (0x0f)
}
}
Name(_CRS, ResourceTemplate() {
IO(Decode16, 0x02f8, 0x02f8, 0x00, 0x08)
IRQNoFlags() { 3 }
})
- }
+} diff --git a/arch/x86/cpu/qemu/acpi/pci-crs.asl b/arch/x86/cpu/qemu/acpi/pci-crs.asl new file mode 100644 index 0000000..43b2858 --- /dev/null +++ b/arch/x86/cpu/qemu/acpi/pci-crs.asl @@ -0,0 +1,61 @@ +/* PCI CRS (current resources) definition. */ +Scope(_SB.PCI0) {
- Name(CRES, ResourceTemplate() {
WordBusNumber(ResourceProducer, MinFixed, MaxFixed, PosDecode,
0x0000, /* Address Space Granularity */
0x0000, /* Address Range Minimum */
0x00ff, /* Address Range Maximum */
0x0000, /* Address Translation Offset */
0x0100, /* Address Length */
,, )
IO(Decode16,
0x0cf8, /* Address Range Minimum */
0x0cf8, /* Address Range Maximum */
0x01, /* Address Alignment */
0x08, /* Address Length */
)
WordIO(ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
0x0000, /* Address Space Granularity */
0x0000, /* Address Range Minimum */
0x0cf7, /* Address Range Maximum */
0x0000, /* Address Translation Offset */
0x0cf8, /* Address Length */
,, , TypeStatic)
WordIO(ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
0x0000, /* Address Space Granularity */
0x0d00, /* Address Range Minimum */
0xffff, /* Address Range Maximum */
0x0000, /* Address Translation Offset */
0xf300, /* Address Length */
,, , TypeStatic)
DWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
0x00000000, /* Address Space Granularity */
0x000a0000, /* Address Range Minimum */
0x000bffff, /* Address Range Maximum */
0x00000000, /* Address Translation Offset */
0x00020000, /* Address Length */
,, , AddressRangeMemory, TypeStatic)
DWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, NonCacheable, ReadWrite,
0x00000000, /* Address Space Granularity */
0xe0000000, /* Address Range Minimum */
0xfebfffff, /* Address Range Maximum */
0x00000000, /* Address Translation Offset */
0x1ec00000, /* Address Length */
,, PW32, AddressRangeMemory, TypeStatic)
- })
- Name(CR64, ResourceTemplate() {
QWordMemory(ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
0x00000000, /* Address Space Granularity */
0x8000000000, /* Address Range Minimum */
0xffffffff, /* Address Range Maximum */
0x00000000, /* Address Translation Offset */
0x8000000000, /* Address Length */
,, PW64, AddressRangeMemory, TypeStatic)
- })
- Method(_CRS, 0) {
Return (CRES)
- }
+} diff --git a/arch/x86/cpu/qemu/dsdt.asl b/arch/x86/cpu/qemu/dsdt.asl new file mode 100644 index 0000000..95c9213 --- /dev/null +++ b/arch/x86/cpu/qemu/dsdt.asl @@ -0,0 +1,414 @@ +/*
- QEMU ACPI DSDT ASL definition
- Copyright (c) 2006 Fabrice Bellard
- Copyright (c) 2010 Isaku Yamahata
yamahata at valinux co jp
- Based on acpi-dsdt.dsl, but heavily modified for q35 chipset.
- */
+DefinitionBlock (
- "dsdt.aml", // Output Filename
- "DSDT", // Signature
- 0x01, // DSDT Compliance Revision
- "UBOO", // OEMID
- "UBOOT ", // TABLE ID
- 0x2 // OEM Revision
Please use C-style comment format.
Addressed in patchset series v6.
- )
+{
+#include "acpi/dbug.asl"
- Scope(_SB) {
OperationRegion(PCST, SystemIO, 0xae00, 0x0c)
OperationRegion(PCSB, SystemIO, 0xae0c, 0x01)
Field(PCSB, AnyAcc, NoLock, WriteAsZeros) {
PCIB, 8,
}
- }
+/****************************************************************
- PCI Bus definition
- ****************************************************************/
/* PCI Bus definition */
Addressed in patchset series v6.
- Scope(_SB) {
Device(PCI0) {
Name(_HID, EisaId("PNP0A08"))
Name(_CID, EisaId("PNP0A03"))
Name(_ADR, 0x00)
Name(_UID, 1)
/* _OSC: based on sample of ACPI3.0b spec */
Name(SUPP, 0) /* PCI _OSC Support Field value */
Name(CTRL, 0) /* PCI _OSC Control Field value */
Method(_OSC, 4) {
/* Create DWORD-addressable fields from Capabilities Buffer */
CreateDWordField(Arg3, 0, CDW1)
// Check for proper UUID
Please use C-style comment format.
Addressed in patchset series v6.
If (LEqual(Arg0, ToUUID("33DB4D5B-1FF7-401C-9657-7441C03DD766")))
{
/* Create DWORD-addressable fields from Capabilities Buffer */
Nits: indention is not correct
Addressed in patchset series v6.
CreateDWordField(Arg3, 4, CDW2)
CreateDWordField(Arg3, 8, CDW3)
/* Save Capabilities DWORD2 & 3 */
Store(CDW2, SUPP)
Store(CDW3, CTRL)
/* Always allow native PME, AER (no dependencies)
Never allow SHPC (no SHPC controller in this system) */
Please use correct multi-line comment.
Addressed in patchset series v6.
And(CTRL, 0x1d, CTRL)
If (LNotEqual(Arg1, One)) {
/* Unknown revision */
Or(CDW1, 0x08, CDW1)
}
If (LNotEqual(CDW3, CTRL)) {
/* Capabilities bits were masked */
Or(CDW1, 0x10, CDW1)
}
/* Update DWORD3 in the buffer */
Store(CTRL, CDW3)
} Else {
Or(CDW1, 4, CDW1) /* Unrecognized UUID */
}
Return (Arg3)
}
}
- }
+#include "acpi/pci-crs.asl" +#include "acpi/hpet.asl"
+/****************************************************************
- VGA
- ****************************************************************/
/* VGA */
Addressed in patchset series v6.
- Scope(_SB.PCI0) {
Device(VGA) {
Name(_ADR, 0x00010000)
Method(_S1D, 0, NotSerialized) {
Return (0x00)
}
Method(_S2D, 0, NotSerialized) {
Return (0x00)
}
Method(_S3D, 0, NotSerialized) {
Return (0x00)
}
}
- }
+/****************************************************************
- LPC ISA bridge
- ****************************************************************/
/* LPC ISA bridge */
Addressed in patchset series v6.
- Scope(_SB.PCI0) {
/* PCI D31:f0 LPC ISA bridge */
Device(ISA) {
/* PCI D31:f0 */
Name(_ADR, 0x001f0000)
/* ICH9 PCI to ISA irq remapping */
OperationRegion(PIRQ, PCI_Config, 0x60, 0x0c)
OperationRegion(LPCD, PCI_Config, 0x80, 0x2)
Field(LPCD, AnyAcc, NoLock, Preserve) {
COMA, 3,
, 1,
COMB, 3,
Offset(0x01),
LPTD, 2,
, 2,
FDCD, 2
}
OperationRegion(LPCE, PCI_Config, 0x82, 0x2)
Field(LPCE, AnyAcc, NoLock, Preserve) {
CAEN, 1,
CBEN, 1,
LPEN, 1,
FDEN, 1
}
}
- }
+#include "acpi/isa.asl"
+/****************************************************************
- PCI IRQs
- ****************************************************************/
/* PCI IRQs */
Addressed in patchset series v6.
- /* Zero => PIC mode, One => APIC Mode */
- Name(\PICF, Zero)
- Method(_PIC, 1, NotSerialized) {
Store(Arg0, \PICF)
- }
- Scope(_SB) {
Scope(PCI0) {
+#define prt_slot_lnk(nr, lnk0, lnk1, lnk2, lnk3) \
- Package() { nr##ffff, 0, lnk0, 0 }, \
- Package() { nr##ffff, 1, lnk1, 0 }, \
- Package() { nr##ffff, 2, lnk2, 0 }, \
- Package() { nr##ffff, 3, lnk3, 0 }
+#define prt_slot_lnkA(nr) prt_slot_lnk(nr, LNKA, LNKB, LNKC, LNKD) +#define prt_slot_lnkB(nr) prt_slot_lnk(nr, LNKB, LNKC, LNKD, LNKA) +#define prt_slot_lnkC(nr) prt_slot_lnk(nr, LNKC, LNKD, LNKA, LNKB) +#define prt_slot_lnkD(nr) prt_slot_lnk(nr, LNKD, LNKA, LNKB, LNKC)
+#define prt_slot_lnkE(nr) prt_slot_lnk(nr, LNKE, LNKF, LNKG, LNKH) +#define prt_slot_lnkF(nr) prt_slot_lnk(nr, LNKF, LNKG, LNKH, LNKE) +#define prt_slot_lnkG(nr) prt_slot_lnk(nr, LNKG, LNKH, LNKE, LNKF) +#define prt_slot_lnkH(nr) prt_slot_lnk(nr, LNKH, LNKE, LNKF, LNKG)
Name(PRTP, Package() {
prt_slot_lnkE(0x0000),
prt_slot_lnkF(0x0001),
prt_slot_lnkG(0x0002),
prt_slot_lnkH(0x0003),
prt_slot_lnkE(0x0004),
prt_slot_lnkF(0x0005),
prt_slot_lnkG(0x0006),
prt_slot_lnkH(0x0007),
prt_slot_lnkE(0x0008),
prt_slot_lnkF(0x0009),
prt_slot_lnkG(0x000a),
prt_slot_lnkH(0x000b),
prt_slot_lnkE(0x000c),
prt_slot_lnkF(0x000d),
prt_slot_lnkG(0x000e),
prt_slot_lnkH(0x000f),
prt_slot_lnkE(0x0010),
prt_slot_lnkF(0x0011),
prt_slot_lnkG(0x0012),
prt_slot_lnkH(0x0013),
prt_slot_lnkE(0x0014),
prt_slot_lnkF(0x0015),
prt_slot_lnkG(0x0016),
prt_slot_lnkH(0x0017),
prt_slot_lnkE(0x0018),
/* INTA -> PIRQA for slot 25 - 31
see the default value of D<N>IR */
prt_slot_lnkA(0x0019),
prt_slot_lnkA(0x001a),
prt_slot_lnkA(0x001b),
prt_slot_lnkA(0x001c),
prt_slot_lnkA(0x001d),
/* PCIe->PCI bridge. use PIRQ[E-H] */
prt_slot_lnkE(0x001e),
prt_slot_lnkA(0x001f)
})
+#define prt_slot_gsi(nr, gsi0, gsi1, gsi2, gsi3) \
- Package() { nr##ffff, 0, gsi0, 0 }, \
- Package() { nr##ffff, 1, gsi1, 0 }, \
- Package() { nr##ffff, 2, gsi2, 0 }, \
- Package() { nr##ffff, 3, gsi3, 0 }
+#define prt_slot_gsiA(nr) prt_slot_gsi(nr, GSIA, GSIB, GSIC, GSID) +#define prt_slot_gsiB(nr) prt_slot_gsi(nr, GSIB, GSIC, GSID, GSIA) +#define prt_slot_gsiC(nr) prt_slot_gsi(nr, GSIC, GSID, GSIA, GSIB) +#define prt_slot_gsiD(nr) prt_slot_gsi(nr, GSID, GSIA, GSIB, GSIC)
+#define prt_slot_gsiE(nr) prt_slot_gsi(nr, GSIE, GSIF, GSIG, GSIH) +#define prt_slot_gsiF(nr) prt_slot_gsi(nr, GSIF, GSIG, GSIH, GSIE) +#define prt_slot_gsiG(nr) prt_slot_gsi(nr, GSIG, GSIH, GSIE, GSIF) +#define prt_slot_gsiH(nr) prt_slot_gsi(nr, GSIH, GSIE, GSIF, GSIG)
Name(PRTA, Package() {
prt_slot_gsiE(0x0000),
prt_slot_gsiF(0x0001),
prt_slot_gsiG(0x0002),
prt_slot_gsiH(0x0003),
prt_slot_gsiE(0x0004),
prt_slot_gsiF(0x0005),
prt_slot_gsiG(0x0006),
prt_slot_gsiH(0x0007),
prt_slot_gsiE(0x0008),
prt_slot_gsiF(0x0009),
prt_slot_gsiG(0x000a),
prt_slot_gsiH(0x000b),
prt_slot_gsiE(0x000c),
prt_slot_gsiF(0x000d),
prt_slot_gsiG(0x000e),
prt_slot_gsiH(0x000f),
prt_slot_gsiE(0x0010),
prt_slot_gsiF(0x0011),
prt_slot_gsiG(0x0012),
prt_slot_gsiH(0x0013),
prt_slot_gsiE(0x0014),
prt_slot_gsiF(0x0015),
prt_slot_gsiG(0x0016),
prt_slot_gsiH(0x0017),
prt_slot_gsiE(0x0018),
/* INTA -> PIRQA for slot 25 - 31, but 30
see the default value of D<N>IR */
Please use correct multi-line comment format.
Addressed in patchset series v6.
prt_slot_gsiA(0x0019),
prt_slot_gsiA(0x001a),
prt_slot_gsiA(0x001b),
prt_slot_gsiA(0x001c),
prt_slot_gsiA(0x001d),
/* PCIe->PCI bridge. use PIRQ[E-H] */
prt_slot_gsiE(0x001e),
prt_slot_gsiA(0x001f)
})
Method(_PRT, 0, NotSerialized) {
/* PCI IRQ routing table, example from ACPI 2.0a specification,
section 6.2.8.1 */
ditto.
Addressed in patchset series v6.
/* Note: we provide the same info as the PCI routing
table of the Bochs BIOS */
ditto.
Addressed in patchset series v6.
If (LEqual(\PICF, Zero)) {
Return (PRTP)
} Else {
Return (PRTA)
}
}
}
Field(PCI0.ISA.PIRQ, ByteAcc, NoLock, Preserve) {
PRQA, 8,
PRQB, 8,
PRQC, 8,
PRQD, 8,
Offset(0x08),
PRQE, 8,
PRQF, 8,
PRQG, 8,
PRQH, 8
}
Method(IQST, 1, NotSerialized) {
/* _STA method - get status */
If (And(0x80, Arg0)) {
Return (0x09)
}
Return (0x0b)
}
Method(IQCR, 1, NotSerialized) {
/* _CRS method - get current settings */
Name(PRR0, ResourceTemplate() {
Interrupt(, Level, ActiveHigh, Shared) { 0 }
})
CreateDWordField(PRR0, 0x05, PRRI)
Store(And(Arg0, 0x0f), PRRI)
Return (PRR0)
}
+#define define_link(link, uid, reg) \
Device(link) { \
Name(_HID, EISAID("PNP0C0F")) \
Name(_UID, uid) \
Name(_PRS, ResourceTemplate() { \
Interrupt(, Level, ActiveHigh, Shared) { \
5, 10, 11 \
} \
}) \
Method(_STA, 0, NotSerialized) { \
Return (IQST(reg)) \
} \
Method(_DIS, 0, NotSerialized) { \
Or(reg, 0x80, reg) \
} \
Method(_CRS, 0, NotSerialized) { \
Return (IQCR(reg)) \
} \
Method(_SRS, 1, NotSerialized) { \
CreateDWordField(Arg0, 0x05, PRRI) \
Store(PRRI, reg) \
} \
}
define_link(LNKA, 0, PRQA)
define_link(LNKB, 1, PRQB)
define_link(LNKC, 2, PRQC)
define_link(LNKD, 3, PRQD)
define_link(LNKE, 4, PRQE)
define_link(LNKF, 5, PRQF)
define_link(LNKG, 6, PRQG)
define_link(LNKH, 7, PRQH)
+#define define_gsi_link(link, uid, gsi) \
Device(link) { \
Name(_HID, EISAID("PNP0C0F")) \
Name(_UID, uid) \
Name(_PRS, ResourceTemplate() { \
Interrupt(, Level, ActiveHigh, Shared) { \
gsi \
} \
}) \
Name(_CRS, ResourceTemplate() { \
Interrupt(, Level, ActiveHigh, Shared) { \
gsi \
} \
}) \
Method(_SRS, 1, NotSerialized) { \
} \
}
define_gsi_link(GSIA, 0, 0x10)
define_gsi_link(GSIB, 0, 0x11)
define_gsi_link(GSIC, 0, 0x12)
define_gsi_link(GSID, 0, 0x13)
define_gsi_link(GSIE, 0, 0x14)
define_gsi_link(GSIF, 0, 0x15)
define_gsi_link(GSIG, 0, 0x16)
define_gsi_link(GSIH, 0, 0x17)
- }
+/****************************************************************
- General purpose events
- ****************************************************************/
/* General purpose events */
Addressed in patchset series v6.
- Scope(_GPE) {
Name(_HID, "ACPI0006")
Method(_L00) {
}
Method(_L01) {
}
Method(_L02) {
}
Method(_L03) {
}
Method(_L04) {
}
Method(_L05) {
}
Method(_L06) {
}
Method(_L07) {
}
Method(_L08) {
}
Method(_L09) {
}
Method(_L0A) {
}
Method(_L0B) {
}
Method(_L0C) {
}
Method(_L0D) {
}
Method(_L0E) {
}
Method(_L0F) {
}
- }
+}
Regards, Bin
Regards, Saket Sinha

Hi Saket,
On Tue, Aug 18, 2015 at 3:29 AM, Saket Sinha saket.sinha89@gmail.com wrote:
ACPI(Advanced Configuration and Power Interface), is a Power Management and configuration standard allowing the operating system to control the amount of power each device is given (allowing it to put certain devices on standby or power-off for example). It is also used to control and/or check thermal zones (temperature sensors, fan speeds, etc), battery levels, PCI IRQ routing, CPUs, NUMA domains and many other things.
Changes in v5:
- Incoporated Simon's review comments.
Please wait until a day or two before you post new version. I haven't got a chance to review v4, but you've already posted v5. Also when you reply our review comments, please keep the U-Boot mailing list cc'ed.
Saket Sinha (3): x86: Generate a valid ACPI table x86: Add ACPI table support to QEMU x86: Add DSDT table for supporting ACPI on QEMU
arch/x86/Kconfig | 9 + arch/x86/cpu/qemu/Makefile | 1 + arch/x86/cpu/qemu/acpi.c | 179 ++++++++++++++ arch/x86/cpu/qemu/acpi/cpu-hotplug.asl | 78 ++++++ arch/x86/cpu/qemu/acpi/dbug.asl | 26 ++ arch/x86/cpu/qemu/acpi/hpet.asl | 33 +++ arch/x86/cpu/qemu/acpi/isa.asl | 102 ++++++++ arch/x86/cpu/qemu/acpi/pci-crs.asl | 61 +++++ arch/x86/cpu/qemu/dsdt.asl | 414 +++++++++++++++++++++++++++++++ arch/x86/include/asm/acpi_table.h | 390 +++++++++++++++++++++++++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/acpi_table.c | 433 +++++++++++++++++++++++++++++++++ arch/x86/lib/tables.c | 5 + scripts/Makefile.lib | 11 + 14 files changed, 1743 insertions(+) create mode 100644 arch/x86/cpu/qemu/acpi.c create mode 100644 arch/x86/cpu/qemu/acpi/cpu-hotplug.asl create mode 100644 arch/x86/cpu/qemu/acpi/dbug.asl create mode 100644 arch/x86/cpu/qemu/acpi/hpet.asl create mode 100644 arch/x86/cpu/qemu/acpi/isa.asl create mode 100644 arch/x86/cpu/qemu/acpi/pci-crs.asl create mode 100644 arch/x86/cpu/qemu/dsdt.asl create mode 100644 arch/x86/include/asm/acpi_table.h create mode 100644 arch/x86/lib/acpi_table.c
--
Regards, Bin

Hi Saket,
On Tue, Aug 18, 2015 at 9:25 AM, Bin Meng bmeng.cn@gmail.com wrote:
Hi Saket,
On Tue, Aug 18, 2015 at 3:29 AM, Saket Sinha saket.sinha89@gmail.com wrote:
ACPI(Advanced Configuration and Power Interface), is a Power Management and configuration standard allowing the operating system to control the amount of power each device is given (allowing it to put certain devices on standby or power-off for example). It is also used to control and/or check thermal zones (temperature sensors, fan speeds, etc), battery levels, PCI IRQ routing, CPUs, NUMA domains and many other things.
Changes in v5:
- Incoporated Simon's review comments.
Please wait until a day or two before you post new version. I haven't got a chance to review v4, but you've already posted v5. Also when you reply our review comments, please keep the U-Boot mailing list cc'ed.
I finished reviewing v5, but still see lots of coding convention issues :( I suggest you read your codes line by line and make sure you do not catch those obvious issues before you send the v6.
Regards, Bin

Hi Saket,
On Tue, Aug 18, 2015 at 3:10 PM, Bin Meng bmeng.cn@gmail.com wrote:
Hi Saket,
On Tue, Aug 18, 2015 at 9:25 AM, Bin Meng bmeng.cn@gmail.com wrote:
Hi Saket,
On Tue, Aug 18, 2015 at 3:29 AM, Saket Sinha saket.sinha89@gmail.com wrote:
ACPI(Advanced Configuration and Power Interface), is a Power Management and configuration standard allowing the operating system to control the amount of power each device is given (allowing it to put certain devices on standby or power-off for example). It is also used to control and/or check thermal zones (temperature sensors, fan speeds, etc), battery levels, PCI IRQ routing, CPUs, NUMA domains and many other things.
Changes in v5:
- Incoporated Simon's review comments.
Please wait until a day or two before you post new version. I haven't got a chance to review v4, but you've already posted v5. Also when you reply our review comments, please keep the U-Boot mailing list cc'ed.
I finished reviewing v5, but still see lots of coding convention issues :( I suggest you read your codes line by line and make sure you do not catch those obvious issues before you send the v6.
Some additional comments:
1). When I applied the patch in my git repo, I got:
$ git am U-Boot-v5-1-3-x86-Generate-a-valid-ACPI-table.patch Applying: x86: Generate a valid ACPI table ~/work/git/u-boot/.git/rebase-apply/patch:428: new blank line at EOF. + ~/git/u-boot/.git/rebase-apply/patch:879: new blank line at EOF. + warning: 2 lines add whitespace errors. $ git am U-Boot-v5-2-3-x86-Add-ACPI-table-support-to-QEMU.patch Applying: x86: Add ACPI table support to QEMU ~/work/git/u-boot/.git/rebase-apply/patch:202: new blank line at EOF. + warning: 1 line adds whitespace errors.
Please fix them too.
2). When I build qemu-x86, I noticed that:
Intel ACPI Component Architecture ASL Optimizing Compiler version 20140828-64 [Sep 18 2014] Copyright (c) 2000 - 2014 Intel Corporation
ASL Input: arch/x86/cpu/qemu/dsdt.asl.tmp - 443 lines, 25927 bytes, 342 keywords Hex Dump: arch/x86/cpu/qemu/dsdt.hex - 65515 bytes
Compilation complete. 1 Errors, 0 Warnings, 1 Remarks, 432 Optimizations
Looks that there is 1 Error? Could you please investigate this?
3). Testing shows that: the Linux kernel graphics console does not work with this series. I've tested that with PIRQ table and MP table, the same kernel image and rootfs does have a working graphics console. Please investigate this.
Regards, Bin

Hi Bin ,
Please find my response inline -
On Tue, Aug 18, 2015 at 2:53 PM, Bin Meng bmeng.cn@gmail.com wrote:
Hi Saket,
On Tue, Aug 18, 2015 at 3:10 PM, Bin Meng bmeng.cn@gmail.com wrote:
Hi Saket,
On Tue, Aug 18, 2015 at 9:25 AM, Bin Meng bmeng.cn@gmail.com wrote:
Hi Saket,
On Tue, Aug 18, 2015 at 3:29 AM, Saket Sinha saket.sinha89@gmail.com wrote:
ACPI(Advanced Configuration and Power Interface), is a Power Management and configuration standard allowing the operating system to control the amount of power each device is given (allowing it to put certain devices on standby or power-off for example). It is also used to control and/or check thermal zones (temperature sensors, fan speeds, etc), battery levels, PCI IRQ routing, CPUs, NUMA domains and many other things.
Changes in v5:
- Incoporated Simon's review comments.
Please wait until a day or two before you post new version. I haven't got a chance to review v4, but you've already posted v5. Also when you reply our review comments, please keep the U-Boot mailing list cc'ed.
I finished reviewing v5, but still see lots of coding convention issues :( I suggest you read your codes line by line and make sure you do not catch those obvious issues before you send the v6.
Some additional comments:
1). When I applied the patch in my git repo, I got:
$ git am U-Boot-v5-1-3-x86-Generate-a-valid-ACPI-table.patch Applying: x86: Generate a valid ACPI table ~/work/git/u-boot/.git/rebase-apply/patch:428: new blank line at EOF.
~/git/u-boot/.git/rebase-apply/patch:879: new blank line at EOF.
warning: 2 lines add whitespace errors. $ git am U-Boot-v5-2-3-x86-Add-ACPI-table-support-to-QEMU.patch Applying: x86: Add ACPI table support to QEMU ~/work/git/u-boot/.git/rebase-apply/patch:202: new blank line at EOF.
warning: 1 line adds whitespace errors.
Please fix them too.
Addressed in patchset series v6.
2). When I build qemu-x86, I noticed that:
Intel ACPI Component Architecture ASL Optimizing Compiler version 20140828-64 [Sep 18 2014] Copyright (c) 2000 - 2014 Intel Corporation
ASL Input: arch/x86/cpu/qemu/dsdt.asl.tmp - 443 lines, 25927 bytes, 342 keywords Hex Dump: arch/x86/cpu/qemu/dsdt.hex - 65515 bytes
Compilation complete. 1 Errors, 0 Warnings, 1 Remarks, 432 Optimizations
Looks that there is 1 Error? Could you please investigate this?
Addressed in patchset series v6.
3). Testing shows that: the Linux kernel graphics console does not work with this series. I've tested that with PIRQ table and MP table, the same kernel image and rootfs does have a working graphics console. Please investigate this.
Yes sadly it does not. What I could debug here is that some values in the qemu dsdt table needs to be fixed to make it working. I can only put it as a TODO now and will dig into the issue deeper to investigate this.
Regards, Bin
Regards, Saket Sinha
participants (2)
-
Bin Meng
-
Saket Sinha