| @@ -1,18 +1,122 @@ | | | @@ -1,18 +1,122 @@ |
1 | /* $NetBSD: xen_acpi_machdep.c,v 1.4 2008/02/17 14:03:16 bouyer Exp $ */ | | 1 | /* $NetBSD: xen_acpi_machdep.c,v 1.4.24.1 2009/06/18 11:14:14 cegger Exp $ */ |
2 | | | 2 | |
3 | #include "acpi.h" | | 3 | #include "acpi.h" |
4 | | | 4 | |
5 | #include <sys/cdefs.h> | | 5 | #include <sys/cdefs.h> |
6 | __KERNEL_RCSID(0, "$NetBSD: xen_acpi_machdep.c,v 1.4 2008/02/17 14:03:16 bouyer Exp $"); | | 6 | __KERNEL_RCSID(0, "$NetBSD: xen_acpi_machdep.c,v 1.4.24.1 2009/06/18 11:14:14 cegger Exp $"); |
7 | | | 7 | |
8 | #include <dev/acpi/acpica.h> | | 8 | #include <dev/acpi/acpica.h> |
9 | #include <dev/acpi/acpivar.h> | | 9 | #include <dev/acpi/acpivar.h> |
10 | #define ACPI_MACHDEP_PRIVATE | | 10 | #define ACPI_MACHDEP_PRIVATE |
11 | #include <machine/acpi_machdep.h> | | 11 | #include <machine/acpi_machdep.h> |
| | | 12 | #include <xen/xen3-public/version.h> |
| | | 13 | |
| | | 14 | static int |
| | | 15 | xen_dom0_sleepenter(int sleep_state, int pm1a_control, int pm1b_control) |
| | | 16 | { |
| | | 17 | struct xen_platform_op op = { |
| | | 18 | .cmd = XENPF_enter_acpi_sleep, |
| | | 19 | .interface_version = XENPF_INTERFACE_VERSION, |
| | | 20 | .u = { |
| | | 21 | .enter_acpi_sleep = { |
| | | 22 | .pm1a_cnt_val = pm1a_control, |
| | | 23 | .pm1b_cnt_val = pm1b_control, |
| | | 24 | .sleep_state = sleep_state, |
| | | 25 | }, |
| | | 26 | }, |
| | | 27 | }; |
| | | 28 | |
| | | 29 | return HYPERVISOR_platform_op(&op); |
| | | 30 | } |
| | | 31 | |
| | | 32 | static ACPI_STATUS |
| | | 33 | acpi_md_get_pm1controls(uint32_t *pm1a_control, uint32_t *pm1b_control) |
| | | 34 | { |
| | | 35 | ACPI_STATUS status = 0; |
| | | 36 | uint32_t pm1a, pm1b; |
| | | 37 | struct acpi_bit_register_info *sleep_type_reg_info; |
| | | 38 | struct acpi_bit_register_info *sleep_enable_reg_info; |
| | | 39 | |
| | | 40 | *pm1a_control = *pm1b_control = 0; |
| | | 41 | |
| | | 42 | sleep_type_reg_info = |
| | | 43 | AcpiHwGetBitRegisterInfo(ACPI_BITREG_SLEEP_TYPE_A); |
| | | 44 | sleep_enable_reg_info = |
| | | 45 | AcpiHwGetBitRegisterInfo(ACPI_BITREG_SLEEP_ENABLE); |
| | | 46 | |
| | | 47 | status = AcpiHwRegisterRead(ACPI_MTX_DO_NOT_LOCK, |
| | | 48 | ACPI_REGISTER_PM1_CONTROL, &pm1a); |
| | | 49 | if (ACPI_FAILURE(status)) |
| | | 50 | return status; |
| | | 51 | |
| | | 52 | /* Clear SLP_EN and SLP_TYP fields */ |
| | | 53 | pm1a &= ~(sleep_type_reg_info->AccessBitMask | |
| | | 54 | sleep_enable_reg_info->AccessBitMask); |
| | | 55 | pm1b = pm1a; |
| | | 56 | |
| | | 57 | /* Insert SLP_TYP bits */ |
| | | 58 | pm1a |= (AcpiGbl_SleepTypeA << sleep_type_reg_info->BitPosition); |
| | | 59 | pm1b |= (AcpiGbl_SleepTypeB << sleep_type_reg_info->BitPosition); |
| | | 60 | |
| | | 61 | /* Split the writes of SLP_TYP and SLP_EN to workaround |
| | | 62 | * poorly implemented hardware |
| | | 63 | */ |
| | | 64 | |
| | | 65 | /* Write #1: fill in SLP_TYP data */ |
| | | 66 | status = AcpiHwRegisterWrite(ACPI_MTX_DO_NOT_LOCK, |
| | | 67 | ACPI_REGISTER_PM1A_CONTROL, |
| | | 68 | pm1a); |
| | | 69 | if (ACPI_FAILURE(status)) |
| | | 70 | return status; |
| | | 71 | |
| | | 72 | status = AcpiHwRegisterWrite(ACPI_MTX_DO_NOT_LOCK, |
| | | 73 | ACPI_REGISTER_PM1B_CONTROL, |
| | | 74 | pm1b); |
| | | 75 | if (ACPI_FAILURE(status)) |
| | | 76 | return status; |
| | | 77 | |
| | | 78 | /* Insert SLP_ENABLE bit */ |
| | | 79 | |
| | | 80 | pm1a |= sleep_enable_reg_info->AccessBitMask; |
| | | 81 | pm1b |= sleep_enable_reg_info->AccessBitMask; |
| | | 82 | |
| | | 83 | ACPI_FLUSH_CPU_CACHE(); |
| | | 84 | |
| | | 85 | *pm1a_control = pm1a; |
| | | 86 | *pm1b_control = pm1b; |
| | | 87 | |
| | | 88 | return status; |
| | | 89 | } |
12 | | | 90 | |
13 | int | | 91 | int |
14 | acpi_md_sleep(int state) | | 92 | acpi_md_sleep(int state) |
15 | { | | 93 | { |
16 | printf("acpi: sleep not implemented\n"); | | 94 | int error; |
17 | return (-1); | | 95 | ACPI_STATUS status; |
| | | 96 | uint32_t pm1a_control, pm1b_control; |
| | | 97 | uint32_t xen_version, xen_vermajor, xen_verminor; |
| | | 98 | |
| | | 99 | xen_version = HYPERVISOR_xen_version(XENVER_version, NULL); |
| | | 100 | xen_vermajor = (xen_version & 0xffff0000) >> 16; |
| | | 101 | xen_verminor = (xen_version & 0x0000ffff); |
| | | 102 | |
| | | 103 | /* Xen version check. We require Xen 3.x */ |
| | | 104 | KASSERT(xen_vermajor >= 3); |
| | | 105 | |
| | | 106 | /* Xen 3.2 and older have no s3 support. */ |
| | | 107 | if (xen_verminor < 3) { |
| | | 108 | printf("xenacpi: Xen 3.2 and older have no S3 support.\n"); |
| | | 109 | return -1; |
| | | 110 | } |
| | | 111 | |
| | | 112 | status = acpi_md_get_pm1controls(&pm1a_control, &pm1b_control); |
| | | 113 | if (ACPI_FAILURE(status)) { |
| | | 114 | printf("xenacpi: can't enter sleep mode. acpi error %i\n", |
| | | 115 | status); |
| | | 116 | return -1; |
| | | 117 | } |
| | | 118 | |
| | | 119 | error = xen_dom0_sleepenter(state, pm1a_control, pm1b_control); |
| | | 120 | |
| | | 121 | return error; |
18 | } | | 122 | } |