Hi,
On Mon, May 20, 2013 at 11:58:22PM -0700, Xiaoguang Sun wrote:
> Add ACPI poweroff so poweroff and shutdown -p can actually work on real
> system with ACPI support.
Nice!
> This patch doesn't use full AML interpreter to look for _S5_, instead it
> uses a way described at here
http://forum.osdev.org/viewtopic.php?t=16990which is simple and good enough.
This is good enough. Have you considered the option that the acpi
driver would provide the information?
I have a few comments, see below. In general, you do not follow the
coding style.
T.
> From 758a7ec01c8430d7a8dc6f8fdea32137516649b8 Mon Sep 17 00:00:00 2001
> From: Xiaoguang Sun <
sun.xi...@yoyosys.com>
> Date: Tue, 21 May 2013 13:26:16 +0800
> Subject: [PATCH] Add acpi poweroff
>
> Use acpi poweroff if it's possible.
> ---
> kernel/arch/i386/acpi.c | 99 ++++++++++++++++++++++++++++++++++++++++++-
> kernel/arch/i386/acpi.h | 66 +++++++++++++++++++++++++++++
> kernel/arch/i386/arch_reset.c | 7 +++
> 3 files changed, 171 insertions(+), 1 deletion(-)
>
> diff --git a/kernel/arch/i386/acpi.c b/kernel/arch/i386/acpi.c
> index 225467b..d2ae46c 100644
> --- a/kernel/arch/i386/acpi.c
> +++ b/kernel/arch/i386/acpi.c
> @@ -24,6 +24,11 @@ static struct {
> } sdt_trans[MAX_RSDT];
>
> static int sdt_count;
> +static u16_t pm1a_cnt_blk = 0;
> +static u16_t pm1b_cnt_blk = 0;
> +static u16_t slp_typa = 0;
Use the same indentation as the files you are changing!
> +static u16_t slp_typb = 0;
> +static u16_t slp_en = 1 << 13;
Define numeral constants so the code is more readable!
> static int acpi_check_csum(struct acpi_sdt_header * tb, size_t size)
> {
> @@ -210,11 +215,85 @@ static int get_acpi_rsdp(void)
> return 0;
> }
>
> +static void acpi_init_poweroff()
Use (void) where the function does not take any arguments.
> +{
> + u8_t *ptr = NULL;
> + u8_t *start = NULL;
> + u8_t *end = NULL;
> + struct acpi_fadt_header *fadt_header = NULL;
> + struct acpi_rsdt * dsdt_header = NULL;
> + char *msg = NULL;
> +
> + /* everything used here existed since ACPI spec 1.0 so we can safely use them */
> + fadt_header = (struct acpi_fadt_header *) acpi_phys2vir(acpi_get_table_base("FACP"));
Do not exceed 80 characters per line, even if it is sometimes difficult.
> + if (fadt_header == NULL) {
> + msg = "Could not load FACP";
> + goto exit;
> + }
> +
> + dsdt_header = (struct acpi_rsdt *) acpi_phys2vir((phys_bytes) fadt_header->dsdt);
> + if (dsdt_header == NULL) {
> + msg = "Could not load DSDT";
> + goto exit;
> + }
> +
> + ptr = start = (u8_t *) dsdt_header->data;
> + end = start + dsdt_header->hdr.length - 4;
> +
> + while (ptr < end && memcmp(ptr, "_S5_", 4) != 0) { ++ptr; }
Put ++ptr on a new line. In general, do not use { } around single
statements unless it is a very long, multi-line one.
Imo, ptr++ is more common than ++ptr in this case.
> +
> + msg = "Could not read S5 data";
> + if (ptr >= end || ptr == start) {
> + goto exit;
> + }
> +
> + /* validate AML structure */
> + if (*(ptr + 4) != 0x12) {
Again, 0x12 should be a meaningful constatnt. This function uses a lot
of constatnts. You could consider using defines from acpica headers,
howeve, redefining them in acpi.h is probably better.
> + goto exit;
> + }
> +
> + if ((ptr < start + 2 || (*(ptr - 2) != 0x08 || *(ptr - 1) != '\\')) && *(ptr - 1) != 0x8) {
> + goto exit;
> + }
> +
> + ptr += 5;
> + if (ptr >= end) {
> + goto exit;
> + }
> +
> + /* package length */
> + ptr += ((*ptr & 0xC0) >> 6) + 2;
> + if (ptr >= end) {
> + goto exit;
> + }
> +
> + if (*ptr == 0xA) {
> + ++ptr; /* skip byte prefix */
> + }
> +
> + slp_typa = (*ptr) << 10;
> +
> + if (*(++ptr) == 0xA) {
> + ++ptr; /* skip byte prefix */
> + }
> + slp_typb = (*ptr) << 10;
> +
> + pm1a_cnt_blk = fadt_header->pm1a_cnt_blk;
> + pm1b_cnt_blk = fadt_header->pm1b_cnt_blk;
> +
> + msg = "poweroff initialized";
> +
> +exit:
> + if (msg) {
> + printf("acpi: %s\n", msg);
> + }
> +}
> +
> void acpi_init(void)
> {
> int s, i;
> read_func = acpi_phys_copy;
> -
> +
Do not introduce unrelated white space changes! Do not leave white
space at the end of lines. Editors can highlight it and git am helps
you when you test whether your patch applies cleanly.
> if (!get_acpi_rsdp()) {
> printf("WARNING : Cannot configure ACPI\n");
> return;
> @@ -239,6 +318,8 @@ void acpi_init(void)
> sdt_trans[i].signature[ACPI_SDT_SIGNATURE_LEN] = '\0';
> sdt_trans[i].length = hdr.length;
> }
> +
> + acpi_init_poweroff();
> }
>
> struct acpi_madt_ioapic * acpi_get_ioapic_next(void)
> @@ -293,3 +374,19 @@ struct acpi_madt_lapic * acpi_get_lapic_next(void)
>
> return ret;
> }
> +
> +void __k_unpaged_acpi_poweroff(void)
> +{
> + /* NO OP poweroff symbol*/
> +}
> +
> +void acpi_poweroff(void)
> +{
> + if (pm1a_cnt_blk == 0) {
> + return;
> + }
> + outw(pm1a_cnt_blk, slp_typa | slp_en);
> + if (pm1b_cnt_blk != 0) {
> + outw(pm1b_cnt_blk, slp_typb | slp_en);
> + }
> +}
> diff --git a/kernel/arch/i386/acpi.h b/kernel/arch/i386/acpi.h
> index ddbd504..132d9d0 100644
> --- a/kernel/arch/i386/acpi.h
> +++ b/kernel/arch/i386/acpi.h
> @@ -30,6 +30,70 @@ struct acpi_sdt_header {
> u32_t creator_revision;
> };
>
> +struct acpi_generic_address {
> + u8_t address_space_id;
> + u8_t register_bit_width;
> + u8_t register_bit_offset;
> + u8_t access_size;
> + u64_t address;
> +};
> +
> +struct acpi_fadt_header
> +{
> + struct acpi_sdt_header hdr;
> + u32_t facs;
> + u32_t dsdt;
> + u8_t model;
> + u8_t preferred_pm_profile;
> + u16_t sci_int;
> + u32_t smi_cmd;
> + u8_t acpi_enable;
> + u8_t acpi_disable;
> + u8_t s4bios_req;
> + u8_t pstate_cnt;
> + u32_t pm1a_evt_blk;
> + u32_t pm1b_evt_blk;
> + u32_t pm1a_cnt_blk;
> + u32_t pm1b_cnt_blk;
> + u32_t pm2_cnt_blk;
> + u32_t pm_tmr_blk;
> + u32_t gpe0_blk;
> + u32_t gpe1_blk;
> + u8_t pm1_evt_len;
> + u8_t pm1_cnt_len;
> + u8_t pm2_cnt_len;
> + u8_t pm_tmr_len;
> + u8_t gpe0_blk_len;
> + u8_t gpe1_blk_len;
> + u8_t gpe1_base;
> + u8_t cst_cnt;
> + u16_t p_lvl2_lat;
> + u16_t p_lvl3_lat;
> + u16_t flush_size;
> + u16_t flush_stride;
> + u8_t duty_offset;
> + u8_t duty_width;
> + u8_t day_alrm;
> + u8_t mon_alrm;
> + u8_t century;
> + u16_t iapc_boot_arch;
> + u8_t reserved1;
> + u32_t flags;
> + struct acpi_generic_address reset_reg;
> + u8_t reset_value;
> + u8_t reserved2[3];
> + u64_t xfacs;
> + u64_t xdsdt;
> + struct acpi_generic_address xpm1a_evt_blk;
> + struct acpi_generic_address xpm1b_evt_blk;
> + struct acpi_generic_address xpm1a_cnt_blk;
> + struct acpi_generic_address xpm1b_cnt_blk;
> + struct acpi_generic_address xpm2_cnt_blk;
> + struct acpi_generic_address xpm_tmr_blk;
> + struct acpi_generic_address xgpe0_blk;
> + struct acpi_generic_address xgpe1_blk;
> +};
> +
> struct acpi_madt_hdr {
> struct acpi_sdt_header hdr;
> u32_t local_apic_address;
> @@ -84,6 +148,8 @@ struct acpi_madt_nmi {
>
> void acpi_init(void);
>
> +void acpi_poweroff(void);
> +
> /*
> * Returns a pointer to the io acpi structure in the MADT table in ACPI. The
> * pointer is valid only until paging is turned off. No memory is allocated in
> diff --git a/kernel/arch/i386/arch_reset.c b/kernel/arch/i386/arch_reset.c
> index 2aad6f0..e75fb5a 100644
> --- a/kernel/arch/i386/arch_reset.c
> +++ b/kernel/arch/i386/arch_reset.c
> @@ -22,6 +22,10 @@
> #include "direct_utils.h"
> #include <machine/multiboot.h>
>
> +#ifdef USE_ACPI
> +#include "acpi.h"
> +#endif
> +
> #define KBCMDP 4 /* kbd controller port (O) */
> #define KBC_PULSE0 0xfe /* pulse output bit 0 */
> #define IO_KBD 0x060 /* 8042 Keyboard */
> @@ -85,6 +89,9 @@ poweroff(void)
> {
> const char *shutdown_str;
>
> +#ifdef USE_ACPI
> + acpi_poweroff();
Test whether ACPI is actually used. It is not by default. Only when
APIC is enabled.
> +#endif
> /* Bochs/QEMU poweroff */
> shutdown_str = "Shutdown";
> while (*shutdown_str) outb(0x8900, *(shutdown_str++));
> --
> 1.7.12.4 (Apple Git-37)
>