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