[U-Boot] [U-BOOT PATCH v3 0/4] x86: This series adds ACPI support for qemu targets.

ACPI(Advanced Configuration and Power Interface), 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.
To begin using ACPI, the operating system must look for the RSDP (Root System Description Pointer). If the RSDP is found, the verification is valid, it contains a pointer to the RSDT (Root System Description Table) and XSDT (extended System Description Table). For the run time part of ACPI the main table to detect is the FADT (Fixed ACPI Description Table) as this contains information needed to enable ACPI. The DSDT table contains a bytecode that is executed by a driver in the kernel.
Changes from v2: - Fixes issues with using MMCONFIG for q35. - Fixes various entries in ACPI tables that OS was not able to parse.
Changes from v1: - Dynamic generation of AML code for DSDT table. -Reading PCI registers for FADT table. -Incorporated review comments.
Saket Sinha (4): x86: Added ACPI support as a configuration option. x86: Added support for ACPI table generation at the generic layer. x86: Added ACPI support for Qemu. x86: Added dsdt tables for Qemu ACPI implementation.
arch/x86/Kconfig | 6 + arch/x86/cpu/qemu/Makefile | 3 +- arch/x86/cpu/qemu/acpi.c | 157 ++++++++++++ arch/x86/cpu/qemu/acpi/cpu-hotplug.asl | 78 ++++++ arch/x86/cpu/qemu/acpi/dbug.asl | 26 ++ arch/x86/cpu/qemu/acpi/hpet.asl | 36 +++ arch/x86/cpu/qemu/acpi/isa.asl | 102 ++++++++ arch/x86/cpu/qemu/acpi/pci-crs.asl | 94 +++++++ arch/x86/cpu/qemu/dsdt.asl | 440 +++++++++++++++++++++++++++++++++ arch/x86/include/asm/acpi_table.h | 387 +++++++++++++++++++++++++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/acpi_table.c | 413 +++++++++++++++++++++++++++++++ arch/x86/lib/tables.c | 5 + scripts/Makefile.lib | 11 + 14 files changed, 1758 insertions(+), 1 deletion(-) 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

Signed-off-by: Saket Sinha saket.sinha89@gmail.com ---
arch/x86/Kconfig | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 01ed760..36eae6d 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -346,6 +346,12 @@ config GENERATE_MP_TABLE
endmenu
+config GENERATE_ACPI_TABLE + bool "Generate ACPI(Advanced Configuration and Power Interface) table" + default y + 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, power management monitoring. + config MAX_PIRQ_LINKS int default 8

Hi Saket,
The patch/commit title is: x86: Added ACPI support as a configuration option.
Please use simple tense in the title. So it's 'Add', not 'Added'. Also please do not add any ending period.
On Thu, Aug 13, 2015 at 11:01 AM, Saket Sinha saket.sinha89@gmail.com wrote:
Please add some commit message to describe what this commit is for.
Signed-off-by: Saket Sinha saket.sinha89@gmail.com
arch/x86/Kconfig | 6 ++++++ 1 file changed, 6 insertions(+)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 01ed760..36eae6d 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -346,6 +346,12 @@ config GENERATE_MP_TABLE
endmenu
+config GENERATE_ACPI_TABLE
Please move this Kconfig option into the "System tables" menu.
bool "Generate ACPI(Advanced Configuration and Power Interface) table"
Please add 'an' before ACPI, and one space after ACPI.
default y
Default should be 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, power management monitoring.
Please rewrite this paragraph, make sure they do not exceed 80 cols.
config MAX_PIRQ_LINKS int default 8 --
Regards, Bin

Signed-off-by: Saket Sinha saket.sinha89@gmail.com ---
arch/x86/include/asm/acpi_table.h | 387 +++++++++++++++++++++++++++++++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/acpi_table.c | 413 ++++++++++++++++++++++++++++++++++++++ arch/x86/lib/tables.c | 5 + scripts/Makefile.lib | 11 + 5 files changed, 817 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/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h new file mode 100644 index 0000000..7b52e7d --- /dev/null +++ b/arch/x86/include/asm/acpi_table.h @@ -0,0 +1,387 @@ +#include <linux/string.h> +#include <malloc.h> +#include <common.h> +#include <asm/post.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 "UBOO" /* Must be exactly 4 bytes long! */ + +#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_STS 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 + +#define ILB_BASE_ADDRESS 0xfed08000 +#define ILB_BASE_SIZE 0x400 + +enum bus_type { + PIC = 0, + APIC = 2, + ETHIGH = 5 +}; + + +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 { + u8 resv; /* Reserved in ACPI 2.0 - 2.0b */ + u8 access_size; /* Access size in ACPI 2.0c/3.0/4.0/5.0 */ + }; + u32 addrl; /* Register address, low 32 bits */ + u32 addrh; /* Register address, high 32 bits */ +} __attribute__ ((packed)) acpi_addr_t; + + +/* RSDP (Root System Description Pointer) */ +struct __packed 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]; +}; +/* Note: ACPI 1.0 didn't have length, xsdt_address, and ext_checksum. */ + +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 */ +/* 0x80-0xbf: Reserved */ +/* 0xc0-0xff: OEM defined */ + +/* 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!) */ + 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 */ +} __attribute__ ((packed)) 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 __packed acpi_rsdt { + struct acpi_table_header header; + u32 entry[MAX_ACPI_TABLES]; +}; + +/* XSDT (Extended System Description Table) */ +struct __packed acpi_xsdt { + struct acpi_table_header header; + u64 entry[MAX_ACPI_TABLES]; +}; + +/* MCFG (PCI Express MMIO config space BAR description table) */ +struct __packed acpi_mcfg { + struct acpi_table_header header; + u8 reserved[8]; +}; + +struct __packed 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 __packed acpi_madt { + struct acpi_table_header header; + u32 lapic_addr; /* Local APIC address */ + u32 flags; /* Multiple APIC flags */ +} __attribute__ ((packed)) 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; + } __attribute__((packed)) path[0]; +} __attribute__ ((packed)) dev_scope_t; + +/* MADT: APIC Structure Types */ +/* TODO: Convert to ALLCAPS. */ +enum acpi_apic_types { + LocalApic = 0, /* Processor local APIC */ + IOApic = 1, /* I/O APIC */ + IRQSourceOverride = 2, /* Interrupt source override */ + NMIType = 3, /* NMI source */ + LocalApicNMI = 4, /* Local APIC NMI */ + LApicAddressOverride = 5, /* Local APIC address override */ + IOSApic = 6, /* I/O SAPIC */ + LocalSApic = 7, /* Local SAPIC */ + PlatformIRQSources = 8, /* Platform interrupt sources */ + Localx2Apic = 9, /* Processor local x2APIC */ + Localx2ApicNMI = 10, /* Local x2APIC NMI */ + /* 0x0b-0x7f: Reserved */ + /* 0x80-0xff: Reserved for OEM use */ +}; + +/* MADT: Processor Local APIC Structure */ +struct __packed 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 */ +}; + +/* MADT: Local APIC NMI Structure */ +struct __packed 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 __packed 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 __packed 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; +}; + +/* FADT TABLE Revision values */ +#define ACPI_FADT_REV_ACPI_1_0 1 +#define ACPI_FADT_REV_ACPI_2_0 3 +#define ACPI_FADT_REV_ACPI_3_0 4 +#define ACPI_FADT_REV_ACPI_4_0 4 +#define ACPI_FADT_REV_ACPI_5_0 5 + +/* 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 */ +enum acpi_fadt_boot_flags { + ACPI_FADT_LEGACY_DEVICES = (1 << 0), + ACPI_FADT_8042 = (1 << 1), + ACPI_FADT_VGA_NOT_PRESENT = (1 << 2), + ACPI_FADT_MSI_NOT_SUPPORTED = (1 << 3), + ACPI_FADT_NO_PCIE_ASPM_CONTROL = (1 << 4), + ACPI_FADT_LEGACY_FREE = 0x00 /* No legacy devices (including 8042) */ +}; +/* FADT Preferred Power Management Profile */ +enum acpi_preferred_pm_profiles { + PM_UNSPECIFIED = 0, + PM_DESKTOP = 1, + PM_MOBILE = 2, + PM_WORKSTATION = 3, + PM_ENTERPRISE_SERVER = 4, + PM_SOHO_SERVER = 5, + PM_APPLIANCE_PC = 6, + PM_PERFORMANCE_SERVER = 7, + PM_TABLET = 8, /* ACPI 5.0 */ +}; + +/* FACS (Firmware ACPI Control Structure) */ +struct __packed 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. */ + +void acpi_add_table(struct acpi_rsdp *rsdp, void *table); +unsigned long write_acpi_tables(unsigned long start); +int acpi_create_madt_lapic(struct acpi_madt_lapic *lapic, u8 cpu, u8 apic); +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_mcfg(unsigned long current); +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_mcfg_mmconfig(struct acpi_mcfg_mmconfig *mmconfig, u32 base, u16 seg_nr, u8 start, u8 end); +int acpi_create_madt_lapic_nmi(struct acpi_madt_lapic_nmi *lapic_nmi, u8 cpu, u16 flags, u8 lint); +static inline uint32_t read32(const void *addr) +{ + return *(volatile uint32_t *)addr; +} + 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..2e20317 --- /dev/null +++ b/arch/x86/lib/acpi_table.c @@ -0,0 +1,413 @@ +/* + * Copyright (C) 2015, Saket Sinha saket.sinha89@gmail.com + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#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> +#include <cpu.h> +#include <dm.h> +#include <dm/uclass-internal.h> +#include <dm/lists.h> + +extern const unsigned char AmlCode[]; + +/** +* Add an ACPI table to the RSDT (and XSDT) structure, recalculate length +* and checksum. +*/ +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... */ + rsdt = (struct acpi_rsdt *)rsdp->rsdt_address; + + /* ...while the XSDT is not. */ + 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: Could not add ACPI table, " + "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; /* Hope this won't get optimized away */ + 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 coreboot. + */ + 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); + } +} + +int acpi_create_madt_lapic(struct acpi_madt_lapic *lapic, u8 cpu, u8 apic) +{ + lapic->type = 0; /* Local APIC structure */ + lapic->length = sizeof(struct acpi_madt_lapic); + lapic->flags = (1 << 0); /* 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 = 1; /* I/O APIC structure */ + 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 = 2; /* Interrupt source override */ + 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 = 4; /* Local APIC NMI structure */ + 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 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. */ + memcpy(header->signature, "APIC", 4); + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + + header->length = sizeof(struct acpi_madt); + header->revision = 1; /* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */ + + madt->lapic_addr = LAPIC_DEFAULT_BASE; + madt->flags = 0x1; /* 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); +} + +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); +} + +/* 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. */ + memcpy(header->signature, "MCFG", 4); + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + + header->length = sizeof(struct acpi_mcfg); + header->revision = 1; + + 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. */ + memcpy(header->signature, "RSDT", 4); + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + + header->length = sizeof(struct acpi_rsdt); + header->revision = 1; /* ACPI 1.0/2.0/3.0/4.0: 1 */ + + /* 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. */ + memcpy(header->signature, "XSDT", 4); + memcpy(header->oem_id, OEM_ID, 6); + memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8); + memcpy(header->asl_compiler_id, ASLC, 4); + + header->length = sizeof(struct acpi_xsdt); + header->revision = 1; /* ACPI 1.0: N/A, 2.0/3.0/4.0: 1 */ + + /* 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 = 0; + } else { + rsdp->xsdt_address = (u64)(u32)xsdt; + rsdp->revision = 2; + } + + /* 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); + ssdt->revision = 2; /* ACPI 1.0/2.0: ?, ACPI 3.0/4.0: 2 */ + memcpy(&ssdt->oem_id, OEM_ID, 6); + memcpy(&ssdt->oem_table_id, oem_table_id, 8); + ssdt->oem_revision = 42; + memcpy(&ssdt->asl_compiler_id, ASLC, 4); + ssdt->asl_compiler_revision = 42; + 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); +} + + +#define ALIGN_CURRENT current = (ALIGN(current, 16)) +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 */ + ALIGN_CURRENT; + + 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); + ALIGN_CURRENT; + rsdt = (struct acpi_rsdt *) current; + current += sizeof(struct acpi_rsdt); + ALIGN_CURRENT; + xsdt = (struct acpi_xsdt *) current; + current += sizeof(struct acpi_xsdt); + ALIGN_CURRENT; + + /* 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); + ALIGN_CURRENT; + + 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); + } + ALIGN_CURRENT; + + debug("ACPI: * FADT\n"); + fadt = (struct acpi_fadt *) current; + current += sizeof(struct acpi_fadt); + ALIGN_CURRENT; + 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; + ALIGN_CURRENT; + 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); + } + ALIGN_CURRENT; + + 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); + ALIGN_CURRENT; + } + + + 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..c259683 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 -tc -p $< -tc $<.tmp; \ + mv $(patsubst %.asl,%.hex,$<) $@ + +$(obj)/%.c: $(src)/%.asl + $(call cmd,acpi_c_asl) + # Bzip2 # ---------------------------------------------------------------------------

Hi Saket,
On Thu, Aug 13, 2015 at 11:01 AM, Saket Sinha saket.sinha89@gmail.com wrote:
Please see my comments in your [1/4] patch regarding to patch title and commit message.
Signed-off-by: Saket Sinha saket.sinha89@gmail.com
arch/x86/include/asm/acpi_table.h | 387 +++++++++++++++++++++++++++++++++++ arch/x86/lib/Makefile | 1 + arch/x86/lib/acpi_table.c | 413 ++++++++++++++++++++++++++++++++++++++ arch/x86/lib/tables.c | 5 + scripts/Makefile.lib | 11 + 5 files changed, 817 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/include/asm/acpi_table.h b/arch/x86/include/asm/acpi_table.h new file mode 100644 index 0000000..7b52e7d --- /dev/null +++ b/arch/x86/include/asm/acpi_table.h @@ -0,0 +1,387 @@
Please add a comment header to give others some hints on where this file is ported from.
+#include <linux/string.h> +#include <malloc.h> +#include <common.h> +#include <asm/post.h>
We should avoid including header files in header file.
+#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 "UBOO" /* Must be exactly 4 bytes long! */
As I mentioned in my review comments to the v2 series, please change ASLC to "INTL" to indicate that we are using Intel ASL compiler to compile ASL files.
+#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_STS 0xb3
We only allow one blank line between code blocks.
+#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
Please remove the space between # and define.
+#define ILB_BASE_ADDRESS 0xfed08000 +#define ILB_BASE_SIZE 0x400
These two macros look chip-specific. Please remove them.
+enum bus_type {
bus_type is too generic, maybe acpi_bus_type?
PIC = 0,
APIC = 2,
ETHIGH = 5
+};
+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 {
u8 resv; /* Reserved in ACPI 2.0 - 2.0b */
u8 access_size; /* Access size in ACPI 2.0c/3.0/4.0/5.0 */
};
The indention is not aligned to others.
u32 addrl; /* Register address, low 32 bits */
u32 addrh; /* Register address, high 32 bits */
+} __attribute__ ((packed)) acpi_addr_t;
I believe this structure is naturally aligned. Please double check.
+/* RSDP (Root System Description Pointer) */ +struct __packed 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];
+};
I believe this structure is naturally aligned. Please double check.
+/* Note: ACPI 1.0 didn't have length, xsdt_address, and ext_checksum. */
This comment should be moved on top of this structure.
+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 */
Please use lower case 0xa.
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 */
Please do not use two spaces after define.
+/* 0x80-0xbf: Reserved */ +/* 0xc0-0xff: OEM defined */
What are these two for?
+/* 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!) */
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 */
+} __attribute__ ((packed)) acpi_header_t;
I believe this structure is naturally aligned. Please double check.
+/* A maximum number of 32 ACPI tables ought to be enough for now. */ +#define MAX_ACPI_TABLES 32
+/* RSDT (Root System Description Table) */ +struct __packed acpi_rsdt {
struct acpi_table_header header;
u32 entry[MAX_ACPI_TABLES];
+};
+/* XSDT (Extended System Description Table) */ +struct __packed acpi_xsdt {
struct acpi_table_header header;
u64 entry[MAX_ACPI_TABLES];
+};
+/* MCFG (PCI Express MMIO config space BAR description table) */ +struct __packed acpi_mcfg {
struct acpi_table_header header;
u8 reserved[8];
+};
+struct __packed 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 __packed acpi_madt {
struct acpi_table_header header;
u32 lapic_addr; /* Local APIC address */
u32 flags; /* Multiple APIC flags */
+} __attribute__ ((packed)) acpi_madt_t;
Please check all the 5 tables above. I believe all of them are naturally aligned.
+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;
} __attribute__((packed)) path[0];
+} __attribute__ ((packed)) dev_scope_t;
Please check __packed is really necessary.
+/* MADT: APIC Structure Types */ +/* TODO: Convert to ALLCAPS. */
Please use multi-line comment format.
+enum acpi_apic_types {
LocalApic = 0, /* Processor local APIC */
IOApic = 1, /* I/O APIC */
IRQSourceOverride = 2, /* Interrupt source override */
NMIType = 3, /* NMI source */
LocalApicNMI = 4, /* Local APIC NMI */
LApicAddressOverride = 5, /* Local APIC address override */
IOSApic = 6, /* I/O SAPIC */
LocalSApic = 7, /* Local SAPIC */
PlatformIRQSources = 8, /* Platform interrupt sources */
Localx2Apic = 9, /* Processor local x2APIC */
Localx2ApicNMI = 10, /* Local x2APIC NMI */
Please do not use CamelCase.
/* 0x0b-0x7f: Reserved */
/* 0x80-0xff: Reserved for OEM use */
+};
+/* MADT: Processor Local APIC Structure */ +struct __packed 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 */
+};
No need for __packed.
+/* MADT: Local APIC NMI Structure */ +struct __packed 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 __packed 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 */
+};
No need for __packed.
+/* MADT: Interrupt Source Override Structure */ +struct __packed 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;
+};
+/* FADT TABLE Revision values */ +#define ACPI_FADT_REV_ACPI_1_0 1 +#define ACPI_FADT_REV_ACPI_2_0 3 +#define ACPI_FADT_REV_ACPI_3_0 4 +#define ACPI_FADT_REV_ACPI_4_0 4 +#define ACPI_FADT_REV_ACPI_5_0 5
Please use enum.
+/* 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 */ +enum acpi_fadt_boot_flags {
ACPI_FADT_LEGACY_DEVICES = (1 << 0),
ACPI_FADT_8042 = (1 << 1),
ACPI_FADT_VGA_NOT_PRESENT = (1 << 2),
ACPI_FADT_MSI_NOT_SUPPORTED = (1 << 3),
ACPI_FADT_NO_PCIE_ASPM_CONTROL = (1 << 4),
ACPI_FADT_LEGACY_FREE = 0x00 /* No legacy devices (including 8042) */
+};
To keep consistency, either move these to plain defines, or convert "FADT Feature Flags" above to enum.
Please add one blank line here.
+/* FADT Preferred Power Management Profile */ +enum acpi_preferred_pm_profiles {
PM_UNSPECIFIED = 0,
PM_DESKTOP = 1,
PM_MOBILE = 2,
PM_WORKSTATION = 3,
PM_ENTERPRISE_SERVER = 4,
PM_SOHO_SERVER = 5,
PM_APPLIANCE_PC = 6,
PM_PERFORMANCE_SERVER = 7,
PM_TABLET = 8, /* ACPI 5.0 */
+};
+/* FACS (Firmware ACPI Control Structure) */ +struct __packed 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. */
+void acpi_add_table(struct acpi_rsdp *rsdp, void *table); +unsigned long write_acpi_tables(unsigned long start); +int acpi_create_madt_lapic(struct acpi_madt_lapic *lapic, u8 cpu, u8 apic); +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_mcfg(unsigned long current); +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_mcfg_mmconfig(struct acpi_mcfg_mmconfig *mmconfig, u32 base, u16 seg_nr, u8 start, u8 end); +int acpi_create_madt_lapic_nmi(struct acpi_madt_lapic_nmi *lapic_nmi, u8 cpu, u16 flags, u8 lint);
Blank line please.
+static inline uint32_t read32(const void *addr) +{
return *(volatile uint32_t *)addr;
+}
What is this?
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..2e20317 --- /dev/null +++ b/arch/x86/lib/acpi_table.c @@ -0,0 +1,413 @@ +/*
- Copyright (C) 2015, Saket Sinha saket.sinha89@gmail.com
Please add comments to give others some hints on where this file is ported from.
- SPDX-License-Identifier: GPL-2.0+
- */
+#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> +#include <cpu.h> +#include <dm.h> +#include <dm/uclass-internal.h> +#include <dm/lists.h>
+extern const unsigned char AmlCode[];
Can we avoid using CamelCase here?
+/** +* Add an ACPI table to the RSDT (and XSDT) structure, recalculate length +* and checksum. +*/ +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... */
rsdt = (struct acpi_rsdt *)rsdp->rsdt_address;
/* ...while the XSDT is not. */
Can we merge this comment to /* The RSDT is mandatory... */?
if (rsdp->xsdt_address)
xsdt = (struct acpi_xsdt *)((u32)rsdp->xsdt_address);
/* This should always be MAX_ACPI_TABLES. */
Nits: please remove the ending period. Please fix this globally in all files.
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: Could not add ACPI table, "
"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; /* Hope this won't get optimized away */
This is suspicious. I guess it might be optimized. Can you double check to create some way that guarantees it won't be optimized?
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 coreboot.
coreboot -> 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));
/* Re-calculate checksum. */
xsdt->header.checksum = 0;
And this might be optimized too.
xsdt->header.checksum = table_compute_checksum((u8 *)xsdt,
xsdt->header.length);
}
+}
+int acpi_create_madt_lapic(struct acpi_madt_lapic *lapic, u8 cpu, u8 apic) +{
lapic->type = 0; /* Local APIC structure */
Please use enum for the type. I mentioned this in the v2 patch.
lapic->length = sizeof(struct acpi_madt_lapic);
lapic->flags = (1 << 0); /* Processor/LAPIC enabled */
Please define this flag as a macro.
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)
The indention is not correct.
+{
ioapic->type = 1; /* I/O APIC structure */
Please use enum for the type.
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 = 2; /* Interrupt source override */
Please use enum for the type.
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)
The indention is not correct.
+{
lapic_nmi->type = 4; /* Local APIC NMI structure */
Please use enum for the type.
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 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. */
memcpy(header->signature, "APIC", 4);
memcpy(header->oem_id, OEM_ID, 6);
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
memcpy(header->asl_compiler_id, ASLC, 4);
Please create a function to fill out the common headers. Looks the only variable here is the table signature.
header->length = sizeof(struct acpi_madt);
header->revision = 1; /* ACPI 1.0/2.0: 1, ACPI 3.0: 2, ACPI 4.0: 3 */
Please use enum for the revision.
madt->lapic_addr = LAPIC_DEFAULT_BASE;
madt->flags = 0x1; /* PCAT_COMPAT */
Please define this flag as a macro.
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);
+}
+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);
+}
+/* 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. */
memcpy(header->signature, "MCFG", 4);
memcpy(header->oem_id, OEM_ID, 6);
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
memcpy(header->asl_compiler_id, ASLC, 4);
Please create a function to fill out the common headers.
header->length = sizeof(struct acpi_mcfg);
header->revision = 1;
Please use enum for the revision.
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 */
Please use enum for the revision.
+}
+static void acpi_write_rsdt(struct acpi_rsdt *rsdt) +{
acpi_header_t *header = &(rsdt->header);
/* Fill out header fields. */
memcpy(header->signature, "RSDT", 4);
memcpy(header->oem_id, OEM_ID, 6);
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
memcpy(header->asl_compiler_id, ASLC, 4);
Please create a function to fill out the common headers.
header->length = sizeof(struct acpi_rsdt);
header->revision = 1; /* ACPI 1.0/2.0/3.0/4.0: 1 */
Please use enum for the revision.
/* 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. */
memcpy(header->signature, "XSDT", 4);
memcpy(header->oem_id, OEM_ID, 6);
memcpy(header->oem_table_id, ACPI_TABLE_CREATOR, 8);
memcpy(header->asl_compiler_id, ASLC, 4);
Please create a function to fill out the common headers.
header->length = sizeof(struct acpi_xsdt);
header->revision = 1; /* ACPI 1.0: N/A, 2.0/3.0/4.0: 1 */
Please use enum for the revision.
/* 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 = 0;
} else {
rsdp->xsdt_address = (u64)(u32)xsdt;
rsdp->revision = 2;
}
/* 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);
ssdt->revision = 2; /* ACPI 1.0/2.0: ?, ACPI 3.0/4.0: 2 */
Please use enum for the revision.
memcpy(&ssdt->oem_id, OEM_ID, 6);
memcpy(&ssdt->oem_table_id, oem_table_id, 8);
ssdt->oem_revision = 42;
Please use defines for the revision.
memcpy(&ssdt->asl_compiler_id, ASLC, 4);
ssdt->asl_compiler_revision = 42;
Please use defines for the 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);
+}
+#define ALIGN_CURRENT current = (ALIGN(current, 16)) +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 */
ALIGN_CURRENT;
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);
ALIGN_CURRENT;
rsdt = (struct acpi_rsdt *) current;
current += sizeof(struct acpi_rsdt);
ALIGN_CURRENT;
xsdt = (struct acpi_xsdt *) current;
current += sizeof(struct acpi_xsdt);
ALIGN_CURRENT;
/* 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);
ALIGN_CURRENT;
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);
}
ALIGN_CURRENT;
debug("ACPI: * FADT\n");
fadt = (struct acpi_fadt *) current;
current += sizeof(struct acpi_fadt);
ALIGN_CURRENT;
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;
ALIGN_CURRENT;
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);
}
ALIGN_CURRENT;
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);
ALIGN_CURRENT;
}
Please remove the blank line.
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..c259683 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 $<; \
Why do we use $(CPP) here?
Can we also suppress the IASL output (see below) to the shell when building U-Boot without 'V=1'?
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 - 442 lines, 25925 bytes, 342 keywords AML Output: arch/x86/cpu/qemu/dsdt.aml - 6952 bytes, 226 named objects, 116 executable opcodes Hex Dump: arch/x86/cpu/qemu/dsdt.hex - 65515 bytes
iasl -tc -p $< -tc $<.tmp; \
There are two -tc here. Duplicated?
mv $(patsubst %.asl,%.hex,$<) $@
+$(obj)/%.c: $(src)/%.asl
$(call cmd,acpi_c_asl)
# Bzip2 # ---------------------------------------------------------------------------
--
Regards, Bin

Signed-off-by: Saket Sinha saket.sinha89@gmail.com ---
arch/x86/cpu/qemu/Makefile | 1 + arch/x86/cpu/qemu/acpi.c | 157 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 158 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..ea2bdc6 --- /dev/null +++ b/arch/x86/cpu/qemu/acpi.c @@ -0,0 +1,157 @@ +#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> +#include <cpu.h> +#include <dm.h> +#include <dm/uclass-internal.h> +#include <dm/lists.h> + +void acpi_create_fadt(struct acpi_fadt *fadt, struct acpi_facs *facs, void *dsdt) +{ + acpi_header_t *header = &(fadt->header); + u16 pmbase; + + /*TODO get this value from pci rather than harcoding it.*/ + 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; + fadt->pm1_cnt_len = 2; /* Upper word is reserved and + Linux complains about 32 bit. */ + 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; + fadt->x_firmware_ctl_l = 0; /* Set X_FIRMWARE_CTRL only if FACS is */ + fadt->x_firmware_ctl_h = 0; /* above 4GB. If X_FIRMWARE_CTRL is set, */ + /* then FIRMWARE_CTRL must be zero. */ + + 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; + fadt->x_pm1a_cnt_blk.bit_width = 16; /* Upper word is reserved and + Linux complains about 32 bit. */ + 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); + + /* Write SB800 IOAPIC, only one */ + 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; +} + +unsigned long acpi_fill_mcfg(unsigned long current) +{ + current += acpi_create_mcfg_mmconfig((struct acpi_mcfg_mmconfig *)current, + 0xe0000000, 0x0, 0x0, 255); + return current; +}

Hi Saket,
On Thu, Aug 13, 2015 at 11:01 AM, Saket Sinha saket.sinha89@gmail.com wrote:
Signed-off-by: Saket Sinha saket.sinha89@gmail.com
arch/x86/cpu/qemu/Makefile | 1 + arch/x86/cpu/qemu/acpi.c | 157 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 158 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..ea2bdc6 --- /dev/null +++ b/arch/x86/cpu/qemu/acpi.c @@ -0,0 +1,157 @@
Missing comment block header.
+#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> +#include <cpu.h> +#include <dm.h> +#include <dm/uclass-internal.h> +#include <dm/lists.h>
Please clean up these header files and only leave the one that is needed by this file.
+void acpi_create_fadt(struct acpi_fadt *fadt, struct acpi_facs *facs, void *dsdt) +{
acpi_header_t *header = &(fadt->header);
u16 pmbase;
/*TODO get this value from pci rather than harcoding it.*/
pmbase = 0x0600;
And I believe the Power Management interface is not working either since no PCI register on QEMU was programmed with a value of 0x600. Please add a TODO if you don't plan to address this in this series.
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;
fadt->pm1_cnt_len = 2; /* Upper word is reserved and
Linux complains about 32 bit. */
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;
fadt->x_firmware_ctl_l = 0; /* Set X_FIRMWARE_CTRL only if FACS is */
fadt->x_firmware_ctl_h = 0; /* above 4GB. If X_FIRMWARE_CTRL is set, */
/* then FIRMWARE_CTRL must be zero. */
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;
fadt->x_pm1a_cnt_blk.bit_width = 16; /* Upper word is reserved and
Linux complains about 32 bit. */
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);
/* Write SB800 IOAPIC, only one */
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);
Can we get these irq value from device tree?
acpi_create_madt_lapic_nmi((struct acpi_madt_lapic_nmi *)current, 0, 0, 0);
return current;
+}
+unsigned long acpi_fill_mcfg(unsigned long current) +{
current += acpi_create_mcfg_mmconfig((struct acpi_mcfg_mmconfig *)current,
0xe0000000, 0x0, 0x0, 255);
As I mentioned several times, please replace the hardcoded 0xe0000000 with CONFIG_PCIE_ECAM_BASE, and this function can be moved to arch/x86/lib/acpi_table.c.
return current;
+}
Regards, Bin

For ACPI, on QEMU x86 emulated platform things like control and/or check thermal zones (temperature sensors, fan speeds, etc), battery levels & power levels do not exist but we can emulate PCI IRQ routing, CPUs, NUMA domains.
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 | 36 +++ arch/x86/cpu/qemu/acpi/isa.asl | 102 ++++++++ arch/x86/cpu/qemu/acpi/pci-crs.asl | 94 +++++++ arch/x86/cpu/qemu/dsdt.asl | 440 +++++++++++++++++++++++++++++++++ 7 files changed, 777 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..8a5a59c 100644 --- a/arch/x86/cpu/qemu/Makefile +++ b/arch/x86/cpu/qemu/Makefile @@ -7,6 +7,6 @@ ifndef CONFIG_EFI_STUB obj-y += car.o dram.o endif -obj-y += qemu.o +obj-y += qemu.o dsdt.o obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.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..0f3e83b --- /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..276321f --- /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..f33e527 --- /dev/null +++ b/arch/x86/cpu/qemu/acpi/hpet.asl @@ -0,0 +1,36 @@ +/**************************************************************** + * 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() { +#if 0 /* This makes WinXP BSOD for not yet figured reasons. */ + IRQNoFlags() {2, 8} +#endif + 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..23761db --- /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..63d1fd5 --- /dev/null +++ b/arch/x86/cpu/qemu/acpi/pci-crs.asl @@ -0,0 +1,94 @@ +/* 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 + 0xFFFFFFFFFF, // Address Range Maximum + 0x00000000, // Address Translation Offset + 0x8000000000, // Address Length + ,, PW64, AddressRangeMemory, TypeStatic) + }) + + Method(_CRS, 0) { +#if 0 + /* Fields provided by dynamically created ssdt */ + External(P0S, IntObj) + External(P0E, IntObj) + External(P1V, IntObj) + External(P1S, BuffObj) + External(P1E, BuffObj) + External(P1L, BuffObj) + + /* fixup 32bit pci io window */ + CreateDWordField(CRES, _SB.PCI0.PW32._MIN, PS32) + CreateDWordField(CRES, _SB.PCI0.PW32._MAX, PE32) + CreateDWordField(CRES, _SB.PCI0.PW32._LEN, PL32) + Store(P0S, PS32) + Store(P0E, PE32) + Store(Add(Subtract(P0E, P0S), 1), PL32) + + If (LEqual(P1V, Zero)) { + Return (CRES) + } + + /* fixup 64bit pci io window */ + CreateQWordField(CR64, _SB.PCI0.PW64._MIN, PS64) + CreateQWordField(CR64, _SB.PCI0.PW64._MAX, PE64) + CreateQWordField(CR64, _SB.PCI0.PW64._LEN, PL64) + Store(P1S, PS64) + Store(P1E, PE64) + Store(P1L, PL64) + /* add window and return result */ + ConcatenateResTemplate(CRES, CR64, Local0) + Return (Local0) +#else + Return (CRES) +#endif + } +} diff --git a/arch/x86/cpu/qemu/dsdt.asl b/arch/x86/cpu/qemu/dsdt.asl new file mode 100644 index 0000000..1e163e2 --- /dev/null +++ b/arch/x86/cpu/qemu/dsdt.asl @@ -0,0 +1,440 @@ +/* + * Bochs/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 the Capabilities Buffer + CreateDWordField(Arg3, 0, CDW1) + + // Check for proper UUID + If (LEqual(Arg0, ToUUID("33DB4D5B-1FF7-401C-9657-7441C03DD766"))) { + // Create DWORD-addressable fields from the 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 0 // For now, nothing to do + If (Not(And(CDW1, 1))) { // Query flag clear? + // Disable GPEs for features granted native control. + If (And(CTRL, 0x01)) { // Hot plug control granted? + Store(0, HPCE) // clear the hot plug SCI enable bit + Store(1, HPCS) // clear the hot plug SCI status bit + } + If (And(CTRL, 0x04)) { // PME control granted? + Store(0, PMCE) // clear the PME SCI enable bit + Store(1, PMCS) // clear the PME SCI status bit + } + If (And(CTRL, 0x10)) { // OS restoring PCI Express cap structure? + // Set status to not restore PCI Express cap structure + // upon resume from S3 + Store(1, S3CR) + } + } +#endif + 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) + } + +#if 0 +#include "cpu-hotplug.asl" +#endif + + +/**************************************************************** + * General purpose events + ****************************************************************/ + + Scope(_GPE) { + Name(_HID, "ACPI0006") + + Method(_L00) { + } + Method(_L01) { +#if 0 + // CPU hotplug event + _SB.PRSC() +#endif + } + 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,
Nits: please replace all places of Qemu to QEMU (all capital letters, as this is the official name)
On Thu, Aug 13, 2015 at 11:01 AM, Saket Sinha saket.sinha89@gmail.com wrote:
For ACPI, on QEMU x86 emulated platform things like control and/or check thermal zones (temperature sensors, fan speeds, etc), battery levels & power levels do not exist but we can emulate PCI IRQ routing, CPUs, NUMA domains.
Please limit the commit message < 80 col each line.
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 | 36 +++ arch/x86/cpu/qemu/acpi/isa.asl | 102 ++++++++ arch/x86/cpu/qemu/acpi/pci-crs.asl | 94 +++++++ arch/x86/cpu/qemu/dsdt.asl | 440 +++++++++++++++++++++++++++++++++ 7 files changed, 777 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..8a5a59c 100644 --- a/arch/x86/cpu/qemu/Makefile +++ b/arch/x86/cpu/qemu/Makefile @@ -7,6 +7,6 @@ ifndef CONFIG_EFI_STUB obj-y += car.o dram.o endif -obj-y += qemu.o +obj-y += qemu.o dsdt.o obj-$(CONFIG_GENERATE_ACPI_TABLE) += acpi.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..0f3e83b --- /dev/null +++ b/arch/x86/cpu/qemu/acpi/cpu-hotplug.asl @@ -0,0 +1,78 @@ +/****************************************************************
- CPU hotplug
- ****************************************************************/
Please use multi-line comment format.
+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 C comment format and fix this globally in this patch.
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..276321f --- /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..f33e527 --- /dev/null +++ b/arch/x86/cpu/qemu/acpi/hpet.asl @@ -0,0 +1,36 @@ +/****************************************************************
- HPET
- ****************************************************************/
+Scope(_SB) {
- Device(HPET) {
Name(_HID, EISAID("PNP0103"))
Name(_UID, 0)
OperationRegion(HPTM, SystemMemory, 0xFED00000, 0x400)
Please use lower case (0xfed00000) hex numbers. Please fix this globally in this patch.
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() {
+#if 0 /* This makes WinXP BSOD for not yet figured reasons. */
IRQNoFlags() {2, 8}
+#endif
Please just remove this #if 0
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..23761db --- /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..63d1fd5 --- /dev/null +++ b/arch/x86/cpu/qemu/acpi/pci-crs.asl @@ -0,0 +1,94 @@ +/* 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
0xFFFFFFFFFF, // Address Range Maximum
0x00000000, // Address Translation Offset
0x8000000000, // Address Length
,, PW64, AddressRangeMemory, TypeStatic)
- })
- Method(_CRS, 0) {
+#if 0
Why #if 0?
/* Fields provided by dynamically created ssdt */
External(P0S, IntObj)
External(P0E, IntObj)
External(P1V, IntObj)
External(P1S, BuffObj)
External(P1E, BuffObj)
External(P1L, BuffObj)
/* fixup 32bit pci io window */
CreateDWordField(CRES, \_SB.PCI0.PW32._MIN, PS32)
CreateDWordField(CRES, \_SB.PCI0.PW32._MAX, PE32)
CreateDWordField(CRES, \_SB.PCI0.PW32._LEN, PL32)
Store(P0S, PS32)
Store(P0E, PE32)
Store(Add(Subtract(P0E, P0S), 1), PL32)
If (LEqual(P1V, Zero)) {
Return (CRES)
}
/* fixup 64bit pci io window */
CreateQWordField(CR64, \_SB.PCI0.PW64._MIN, PS64)
CreateQWordField(CR64, \_SB.PCI0.PW64._MAX, PE64)
CreateQWordField(CR64, \_SB.PCI0.PW64._LEN, PL64)
Store(P1S, PS64)
Store(P1E, PE64)
Store(P1L, PL64)
/* add window and return result */
ConcatenateResTemplate(CRES, CR64, Local0)
Return (Local0)
+#else
Return (CRES)
+#endif
- }
+} diff --git a/arch/x86/cpu/qemu/dsdt.asl b/arch/x86/cpu/qemu/dsdt.asl new file mode 100644 index 0000000..1e163e2 --- /dev/null +++ b/arch/x86/cpu/qemu/dsdt.asl @@ -0,0 +1,440 @@ +/*
- Bochs/QEMU ACPI DSDT ASL definition
Just QEMU.
- 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 the Capabilities Buffer
CreateDWordField(Arg3, 0, CDW1)
// Check for proper UUID
If (LEqual(Arg0, ToUUID("33DB4D5B-1FF7-401C-9657-7441C03DD766"))) {
// Create DWORD-addressable fields from the 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 0 // For now, nothing to do
If not needed, please just remove.
If (Not(And(CDW1, 1))) { // Query flag clear?
// Disable GPEs for features granted native control.
If (And(CTRL, 0x01)) { // Hot plug control granted?
Store(0, HPCE) // clear the hot plug SCI enable bit
Store(1, HPCS) // clear the hot plug SCI status bit
}
If (And(CTRL, 0x04)) { // PME control granted?
Store(0, PMCE) // clear the PME SCI enable bit
Store(1, PMCS) // clear the PME SCI status bit
}
If (And(CTRL, 0x10)) { // OS restoring PCI Express cap structure?
// Set status to not restore PCI Express cap structure
// upon resume from S3
Store(1, S3CR)
}
}
+#endif
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)
- }
+#if 0 +#include "cpu-hotplug.asl" +#endif
Why #if 0?
+/****************************************************************
- General purpose events
- ****************************************************************/
- Scope(_GPE) {
Name(_HID, "ACPI0006")
Method(_L00) {
}
Method(_L01) {
+#if 0
// CPU hotplug event
\_SB.PRSC()
+#endif
Why #if 0?
}
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 Saket,
On Thu, Aug 13, 2015 at 11:00 AM, Saket Sinha saket.sinha89@gmail.com wrote:
ACPI(Advanced Configuration and Power Interface), 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.
To begin using ACPI, the operating system must look for the RSDP (Root System Description Pointer). If the RSDP is found, the verification is valid, it contains a pointer to the RSDT (Root System Description Table) and XSDT (extended System Description Table). For the run time part of ACPI the main table to detect is the FADT (Fixed ACPI Description Table) as this contains information needed to enable ACPI. The DSDT table contains a bytecode that is executed by a driver in the kernel.
I've only finished reviewing the first 2 patches today. Some general comments regarding to this patch set:
- Some of my previous comments against v1/v2 series are not completely addressed. I still see them in this v3. - There are building warnings of qemu with this patch - There are lots of coding convention issues here and there like 80 cols. Can you please make sure before you submit the patch, run patman or checkpatch.pl to make sure it is in a good shape?
Changes from v2:
- Fixes issues with using MMCONFIG for q35.
- Fixes various entries in ACPI tables that OS was not able to parse.
Changes from v1:
- Dynamic generation of AML code for DSDT table.
-Reading PCI registers for FADT table. -Incorporated review comments.
Regards, Bin
participants (2)
-
Bin Meng
-
Saket Sinha