1 /*
2 * acpi_osl.c - OS-dependent functions ($Revision: 83 $)
3 *
4 * Copyright (C) 2000 Andrew Henroid
5 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
6 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
7 *
8 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; If not, see <http://www.gnu.org/licenses/>.
22 *
23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24 *
25 */
26 #include <asm/io.h>
27 #include <xen/init.h>
28 #include <xen/pfn.h>
29 #include <xen/types.h>
30 #include <xen/errno.h>
31 #include <xen/acpi.h>
32 #include <xen/numa.h>
33 #include <acpi/acmacros.h>
34 #include <acpi/acpiosxf.h>
35 #include <acpi/platform/aclinux.h>
36 #include <xen/spinlock.h>
37 #include <xen/domain_page.h>
38 #include <xen/efi.h>
39 #include <xen/vmap.h>
40
41 #define _COMPONENT ACPI_OS_SERVICES
42 ACPI_MODULE_NAME("osl")
43
44 #ifdef CONFIG_ACPI_CUSTOM_DSDT
45 #include CONFIG_ACPI_CUSTOM_DSDT_FILE
46 #endif
47
acpi_os_printf(const char * fmt,...)48 void __init acpi_os_printf(const char *fmt, ...)
49 {
50 va_list args;
51 va_start(args, fmt);
52 acpi_os_vprintf(fmt, args);
53 va_end(args);
54 }
55
acpi_os_vprintf(const char * fmt,va_list args)56 void __init acpi_os_vprintf(const char *fmt, va_list args)
57 {
58 static char buffer[512];
59
60 vsnprintf(buffer, sizeof(buffer), fmt, args);
61
62 printk("%s", buffer);
63 }
64
acpi_os_get_root_pointer(void)65 acpi_physical_address __init acpi_os_get_root_pointer(void)
66 {
67 if (efi_enabled(EFI_BOOT)) {
68 if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
69 return efi.acpi20;
70 else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
71 return efi.acpi;
72 else {
73 printk(KERN_ERR PREFIX
74 "System description tables not found\n");
75 return 0;
76 }
77 } else if (IS_ENABLED(CONFIG_ACPI_LEGACY_TABLES_LOOKUP)) {
78 acpi_physical_address pa = 0;
79
80 acpi_find_root_pointer(&pa);
81 return pa;
82 }
83
84 return 0;
85 }
86
87 void __iomem *
acpi_os_map_memory(acpi_physical_address phys,acpi_size size)88 acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
89 {
90 if (system_state >= SYS_STATE_boot) {
91 mfn_t mfn = _mfn(PFN_DOWN(phys));
92 unsigned int offs = phys & (PAGE_SIZE - 1);
93
94 /* The low first Mb is always mapped on x86. */
95 if (IS_ENABLED(CONFIG_X86) && !((phys + size - 1) >> 20))
96 return __va(phys);
97 return __vmap(&mfn, PFN_UP(offs + size), 1, 1,
98 ACPI_MAP_MEM_ATTR, VMAP_DEFAULT) + offs;
99 }
100 return __acpi_map_table(phys, size);
101 }
102
acpi_os_unmap_memory(void __iomem * virt,acpi_size size)103 void acpi_os_unmap_memory(void __iomem * virt, acpi_size size)
104 {
105 if (IS_ENABLED(CONFIG_X86) &&
106 (unsigned long)virt >= DIRECTMAP_VIRT_START &&
107 (unsigned long)virt < DIRECTMAP_VIRT_END) {
108 ASSERT(!((__pa(virt) + size - 1) >> 20));
109 return;
110 }
111
112 if (system_state >= SYS_STATE_boot)
113 vunmap((void *)((unsigned long)virt & PAGE_MASK));
114 }
115
acpi_os_read_port(acpi_io_address port,u32 * value,u32 width)116 acpi_status acpi_os_read_port(acpi_io_address port, u32 * value, u32 width)
117 {
118 u32 dummy;
119
120 if (!value)
121 value = &dummy;
122
123 *value = 0;
124 if (width <= 8) {
125 *(u8 *) value = inb(port);
126 } else if (width <= 16) {
127 *(u16 *) value = inw(port);
128 } else if (width <= 32) {
129 *(u32 *) value = inl(port);
130 } else {
131 BUG();
132 }
133
134 return AE_OK;
135 }
136
acpi_os_write_port(acpi_io_address port,u32 value,u32 width)137 acpi_status acpi_os_write_port(acpi_io_address port, u32 value, u32 width)
138 {
139 if (width <= 8) {
140 outb(value, port);
141 } else if (width <= 16) {
142 outw(value, port);
143 } else if (width <= 32) {
144 outl(value, port);
145 } else {
146 BUG();
147 }
148
149 return AE_OK;
150 }
151
152 acpi_status
acpi_os_read_memory(acpi_physical_address phys_addr,u32 * value,u32 width)153 acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
154 {
155 u32 dummy;
156 void __iomem *virt_addr = acpi_os_map_memory(phys_addr, width >> 3);
157
158 if (!virt_addr)
159 return AE_ERROR;
160
161 if (!value)
162 value = &dummy;
163
164 switch (width) {
165 case 8:
166 *(u8 *) value = readb(virt_addr);
167 break;
168 case 16:
169 *(u16 *) value = readw(virt_addr);
170 break;
171 case 32:
172 *(u32 *) value = readl(virt_addr);
173 break;
174 default:
175 BUG();
176 }
177
178 acpi_os_unmap_memory(virt_addr, width >> 3);
179
180 return AE_OK;
181 }
182
183 acpi_status
acpi_os_write_memory(acpi_physical_address phys_addr,u32 value,u32 width)184 acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
185 {
186 void __iomem *virt_addr = acpi_os_map_memory(phys_addr, width >> 3);
187
188 if (!virt_addr)
189 return AE_ERROR;
190
191 switch (width) {
192 case 8:
193 writeb(value, virt_addr);
194 break;
195 case 16:
196 writew(value, virt_addr);
197 break;
198 case 32:
199 writel(value, virt_addr);
200 break;
201 default:
202 BUG();
203 }
204
205 acpi_os_unmap_memory(virt_addr, width >> 3);
206
207 return AE_OK;
208 }
209
210 #define is_xmalloc_memory(ptr) ((unsigned long)(ptr) & (PAGE_SIZE - 1))
211
acpi_os_alloc_memory(size_t sz)212 void *__init acpi_os_alloc_memory(size_t sz)
213 {
214 void *ptr;
215
216 if (system_state == SYS_STATE_early_boot)
217 return mfn_to_virt(mfn_x(alloc_boot_pages(PFN_UP(sz), 1)));
218
219 ptr = xmalloc_bytes(sz);
220 ASSERT(!ptr || is_xmalloc_memory(ptr));
221 return ptr;
222 }
223
acpi_os_zalloc_memory(size_t sz)224 void *__init acpi_os_zalloc_memory(size_t sz)
225 {
226 void *ptr;
227
228 if (system_state != SYS_STATE_early_boot) {
229 ptr = xzalloc_bytes(sz);
230 ASSERT(!ptr || is_xmalloc_memory(ptr));
231 return ptr;
232 }
233 ptr = acpi_os_alloc_memory(sz);
234 return ptr ? memset(ptr, 0, sz) : NULL;
235 }
236
acpi_os_free_memory(void * ptr)237 void __init acpi_os_free_memory(void *ptr)
238 {
239 if (is_xmalloc_memory(ptr))
240 xfree(ptr);
241 else if (ptr && system_state == SYS_STATE_early_boot)
242 init_boot_pages(__pa(ptr), __pa(ptr) + PAGE_SIZE);
243 }
244