/root/src/xen/xen/arch/x86/acpi/lib.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * lib.c - Architecture-Specific Low-Level ACPI Support |
3 | | * |
4 | | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify |
7 | | * it under the terms of the GNU General Public License as published by |
8 | | * the Free Software Foundation; either version 2 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * This program is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU General Public License |
17 | | * along with this program; If not, see <http://www.gnu.org/licenses/>. |
18 | | * |
19 | | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
20 | | */ |
21 | | |
22 | | #include <xen/errno.h> |
23 | | #include <xen/init.h> |
24 | | #include <xen/acpi.h> |
25 | | #include <asm/apic.h> |
26 | | #include <asm/fixmap.h> |
27 | | |
28 | | u32 __read_mostly acpi_smi_cmd; |
29 | | u8 __read_mostly acpi_enable_value; |
30 | | u8 __read_mostly acpi_disable_value; |
31 | | |
32 | | u32 __read_mostly x86_acpiid_to_apicid[MAX_MADT_ENTRIES] = |
33 | | {[0 ... MAX_MADT_ENTRIES - 1] = BAD_APICID }; |
34 | | |
35 | | /* |
36 | | * Important Safety Note: The fixed ACPI page numbers are *subtracted* |
37 | | * from the fixed base. That's why we start at FIX_ACPI_END and |
38 | | * count idx down while incrementing the phys address. |
39 | | */ |
40 | | char *__acpi_map_table(paddr_t phys, unsigned long size) |
41 | 27 | { |
42 | 27 | unsigned long base, offset, mapped_size; |
43 | 27 | int idx; |
44 | 27 | |
45 | 27 | /* XEN: RAM holes above 1MB are not permanently mapped. */ |
46 | 27 | if ((phys + size) <= (1 * 1024 * 1024)) |
47 | 5 | return __va(phys); |
48 | 27 | |
49 | 22 | offset = phys & (PAGE_SIZE - 1); |
50 | 22 | mapped_size = PAGE_SIZE - offset; |
51 | 22 | set_fixmap(FIX_ACPI_END, phys); |
52 | 22 | base = fix_to_virt(FIX_ACPI_END); |
53 | 22 | |
54 | 22 | /* |
55 | 22 | * Most cases can be covered by the below. |
56 | 22 | */ |
57 | 22 | idx = FIX_ACPI_END; |
58 | 22 | while (mapped_size < size) { |
59 | 0 | if (--idx < FIX_ACPI_BEGIN) |
60 | 0 | return NULL; /* cannot handle this */ |
61 | 0 | phys += PAGE_SIZE; |
62 | 0 | set_fixmap(idx, phys); |
63 | 0 | mapped_size += PAGE_SIZE; |
64 | 0 | } |
65 | 22 | |
66 | 22 | return ((char *) base + offset); |
67 | 22 | } |
68 | | |
69 | | unsigned int acpi_get_processor_id(unsigned int cpu) |
70 | 0 | { |
71 | 0 | unsigned int acpiid, apicid; |
72 | 0 |
|
73 | 0 | if ((apicid = x86_cpu_to_apicid[cpu]) == BAD_APICID) |
74 | 0 | return INVALID_ACPIID; |
75 | 0 |
|
76 | 0 | for (acpiid = 0; acpiid < ARRAY_SIZE(x86_acpiid_to_apicid); acpiid++) |
77 | 0 | if (x86_acpiid_to_apicid[acpiid] == apicid) |
78 | 0 | return acpiid; |
79 | 0 |
|
80 | 0 | return INVALID_ACPIID; |
81 | 0 | } |
82 | | |
83 | | static void get_mwait_ecx(void *info) |
84 | 0 | { |
85 | 0 | *(u32 *)info = cpuid_ecx(CPUID_MWAIT_LEAF); |
86 | 0 | } |
87 | | |
88 | | int arch_acpi_set_pdc_bits(u32 acpi_id, u32 *pdc, u32 mask) |
89 | 0 | { |
90 | 0 | unsigned int cpu = get_cpu_id(acpi_id); |
91 | 0 | struct cpuinfo_x86 *c; |
92 | 0 | u32 ecx; |
93 | 0 |
|
94 | 0 | if (!(acpi_id + 1)) |
95 | 0 | c = &boot_cpu_data; |
96 | 0 | else if (cpu >= nr_cpu_ids || !cpu_online(cpu)) |
97 | 0 | return -EINVAL; |
98 | 0 | else |
99 | 0 | c = cpu_data + cpu; |
100 | 0 |
|
101 | 0 | pdc[2] |= ACPI_PDC_C_CAPABILITY_SMP & mask; |
102 | 0 |
|
103 | 0 | if (cpu_has(c, X86_FEATURE_EIST)) |
104 | 0 | pdc[2] |= ACPI_PDC_EST_CAPABILITY_SWSMP & mask; |
105 | 0 |
|
106 | 0 | if (cpu_has(c, X86_FEATURE_ACPI)) |
107 | 0 | pdc[2] |= ACPI_PDC_T_FFH & mask; |
108 | 0 |
|
109 | 0 | /* |
110 | 0 | * If mwait/monitor or its break-on-interrupt extension are |
111 | 0 | * unsupported, Cx_FFH will be disabled. |
112 | 0 | */ |
113 | 0 | if (!cpu_has(c, X86_FEATURE_MONITOR) || |
114 | 0 | c->cpuid_level < CPUID_MWAIT_LEAF) |
115 | 0 | ecx = 0; |
116 | 0 | else if (c == &boot_cpu_data || cpu == smp_processor_id()) |
117 | 0 | ecx = cpuid_ecx(CPUID_MWAIT_LEAF); |
118 | 0 | else |
119 | 0 | on_selected_cpus(cpumask_of(cpu), get_mwait_ecx, &ecx, 1); |
120 | 0 | if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED) || |
121 | 0 | !(ecx & CPUID5_ECX_INTERRUPT_BREAK)) |
122 | 0 | pdc[2] &= ~(ACPI_PDC_C_C1_FFH | ACPI_PDC_C_C2C3_FFH); |
123 | 0 |
|
124 | 0 | return 0; |
125 | 0 | } |