Commit | Line | Data |
---|---|---|
c942fddf | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
1da177e4 LT |
2 | /* |
3 | * acpi_osl.c - OS-dependent functions ($Revision: 83 $) | |
4 | * | |
5 | * Copyright (C) 2000 Andrew Henroid | |
6 | * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> | |
7 | * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> | |
f1241c87 MW |
8 | * Copyright (c) 2008 Intel Corporation |
9 | * Author: Matthew Wilcox <willy@linux.intel.com> | |
1da177e4 LT |
10 | */ |
11 | ||
1da177e4 LT |
12 | #include <linux/module.h> |
13 | #include <linux/kernel.h> | |
14 | #include <linux/slab.h> | |
15 | #include <linux/mm.h> | |
ba242d5b | 16 | #include <linux/highmem.h> |
bee6f871 | 17 | #include <linux/lockdep.h> |
1da177e4 | 18 | #include <linux/pci.h> |
1da177e4 LT |
19 | #include <linux/interrupt.h> |
20 | #include <linux/kmod.h> | |
21 | #include <linux/delay.h> | |
22 | #include <linux/workqueue.h> | |
23 | #include <linux/nmi.h> | |
ad71860a | 24 | #include <linux/acpi.h> |
1da177e4 | 25 | #include <linux/efi.h> |
df92e695 TR |
26 | #include <linux/ioport.h> |
27 | #include <linux/list.h> | |
f1241c87 MW |
28 | #include <linux/jiffies.h> |
29 | #include <linux/semaphore.h> | |
41fa1ee9 | 30 | #include <linux/security.h> |
f1241c87 MW |
31 | |
32 | #include <asm/io.h> | |
7c0f6ba6 | 33 | #include <linux/uaccess.h> |
2f8e2c87 | 34 | #include <linux/io-64-nonatomic-lo-hi.h> |
f1241c87 | 35 | |
d2d2e3c4 HK |
36 | #include "acpica/accommon.h" |
37 | #include "acpica/acnamesp.h" | |
1129c92f | 38 | #include "internal.h" |
1da177e4 | 39 | |
1da177e4 | 40 | #define _COMPONENT ACPI_OS_SERVICES |
f52fd66d | 41 | ACPI_MODULE_NAME("osl"); |
07070e12 | 42 | |
4be44fcd LB |
43 | struct acpi_os_dpc { |
44 | acpi_osd_exec_callback function; | |
45 | void *context; | |
65f27f38 | 46 | struct work_struct work; |
1da177e4 LT |
47 | }; |
48 | ||
1da177e4 LT |
49 | #ifdef ENABLE_DEBUGGER |
50 | #include <linux/kdb.h> | |
51 | ||
52 | /* stuff for debugger support */ | |
53 | int acpi_in_debugger; | |
54 | EXPORT_SYMBOL(acpi_in_debugger); | |
4be44fcd | 55 | #endif /*ENABLE_DEBUGGER */ |
1da177e4 | 56 | |
09f98a82 TL |
57 | static int (*__acpi_os_prepare_sleep)(u8 sleep_state, u32 pm1a_ctrl, |
58 | u32 pm1b_ctrl); | |
d6b47b12 BG |
59 | static int (*__acpi_os_prepare_extended_sleep)(u8 sleep_state, u32 val_a, |
60 | u32 val_b); | |
09f98a82 | 61 | |
1da177e4 LT |
62 | static acpi_osd_handler acpi_irq_handler; |
63 | static void *acpi_irq_context; | |
64 | static struct workqueue_struct *kacpid_wq; | |
88db5e14 | 65 | static struct workqueue_struct *kacpi_notify_wq; |
92d8aff3 | 66 | static struct workqueue_struct *kacpi_hotplug_wq; |
7901a052 | 67 | static bool acpi_os_initialized; |
49e4b843 | 68 | unsigned int acpi_sci_irq = INVALID_ACPI_IRQ; |
8d3523fb | 69 | bool acpi_permanent_mmap = false; |
1da177e4 | 70 | |
620242ae MS |
71 | /* |
72 | * This list of permanent mappings is for memory that may be accessed from | |
73 | * interrupt context, where we can't do the ioremap(). | |
74 | */ | |
75 | struct acpi_ioremap { | |
76 | struct list_head list; | |
77 | void __iomem *virt; | |
78 | acpi_physical_address phys; | |
79 | acpi_size size; | |
b7c1fadd | 80 | unsigned long refcount; |
620242ae MS |
81 | }; |
82 | ||
83 | static LIST_HEAD(acpi_ioremaps); | |
7bbb8903 | 84 | static DEFINE_MUTEX(acpi_ioremap_lock); |
bee6f871 | 85 | #define acpi_ioremap_lock_held() lock_is_held(&acpi_ioremap_lock.dep_map) |
620242ae | 86 | |
bc9ffce2 | 87 | static void __init acpi_request_region (struct acpi_generic_address *gas, |
9a47cdb1 BH |
88 | unsigned int length, char *desc) |
89 | { | |
bc9ffce2 MS |
90 | u64 addr; |
91 | ||
92 | /* Handle possible alignment issues */ | |
93 | memcpy(&addr, &gas->address, sizeof(addr)); | |
94 | if (!addr || !length) | |
9a47cdb1 BH |
95 | return; |
96 | ||
0294112e RW |
97 | /* Resources are never freed */ |
98 | if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) | |
99 | request_region(addr, length, desc); | |
100 | else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) | |
101 | request_mem_region(addr, length, desc); | |
9a47cdb1 BH |
102 | } |
103 | ||
0294112e | 104 | static int __init acpi_reserve_resources(void) |
9a47cdb1 | 105 | { |
eee3c859 | 106 | acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length, |
9a47cdb1 BH |
107 | "ACPI PM1a_EVT_BLK"); |
108 | ||
eee3c859 | 109 | acpi_request_region(&acpi_gbl_FADT.xpm1b_event_block, acpi_gbl_FADT.pm1_event_length, |
9a47cdb1 BH |
110 | "ACPI PM1b_EVT_BLK"); |
111 | ||
eee3c859 | 112 | acpi_request_region(&acpi_gbl_FADT.xpm1a_control_block, acpi_gbl_FADT.pm1_control_length, |
9a47cdb1 BH |
113 | "ACPI PM1a_CNT_BLK"); |
114 | ||
eee3c859 | 115 | acpi_request_region(&acpi_gbl_FADT.xpm1b_control_block, acpi_gbl_FADT.pm1_control_length, |
9a47cdb1 BH |
116 | "ACPI PM1b_CNT_BLK"); |
117 | ||
eee3c859 LB |
118 | if (acpi_gbl_FADT.pm_timer_length == 4) |
119 | acpi_request_region(&acpi_gbl_FADT.xpm_timer_block, 4, "ACPI PM_TMR"); | |
9a47cdb1 | 120 | |
eee3c859 | 121 | acpi_request_region(&acpi_gbl_FADT.xpm2_control_block, acpi_gbl_FADT.pm2_control_length, |
9a47cdb1 BH |
122 | "ACPI PM2_CNT_BLK"); |
123 | ||
124 | /* Length of GPE blocks must be a non-negative multiple of 2 */ | |
125 | ||
eee3c859 LB |
126 | if (!(acpi_gbl_FADT.gpe0_block_length & 0x1)) |
127 | acpi_request_region(&acpi_gbl_FADT.xgpe0_block, | |
128 | acpi_gbl_FADT.gpe0_block_length, "ACPI GPE0_BLK"); | |
9a47cdb1 | 129 | |
eee3c859 LB |
130 | if (!(acpi_gbl_FADT.gpe1_block_length & 0x1)) |
131 | acpi_request_region(&acpi_gbl_FADT.xgpe1_block, | |
132 | acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK"); | |
0294112e RW |
133 | |
134 | return 0; | |
9a47cdb1 | 135 | } |
0294112e | 136 | fs_initcall_sync(acpi_reserve_resources); |
9a47cdb1 | 137 | |
4be44fcd | 138 | void acpi_os_printf(const char *fmt, ...) |
1da177e4 LT |
139 | { |
140 | va_list args; | |
141 | va_start(args, fmt); | |
142 | acpi_os_vprintf(fmt, args); | |
143 | va_end(args); | |
144 | } | |
836d0830 | 145 | EXPORT_SYMBOL(acpi_os_printf); |
4be44fcd | 146 | |
4be44fcd | 147 | void acpi_os_vprintf(const char *fmt, va_list args) |
1da177e4 LT |
148 | { |
149 | static char buffer[512]; | |
4be44fcd | 150 | |
1da177e4 LT |
151 | vsprintf(buffer, fmt, args); |
152 | ||
153 | #ifdef ENABLE_DEBUGGER | |
154 | if (acpi_in_debugger) { | |
155 | kdb_printf("%s", buffer); | |
156 | } else { | |
abc4b9a5 JP |
157 | if (printk_get_level(buffer)) |
158 | printk("%s", buffer); | |
159 | else | |
160 | printk(KERN_CONT "%s", buffer); | |
1da177e4 LT |
161 | } |
162 | #else | |
abc4b9a5 JP |
163 | if (acpi_debugger_write_log(buffer) < 0) { |
164 | if (printk_get_level(buffer)) | |
165 | printk("%s", buffer); | |
166 | else | |
167 | printk(KERN_CONT "%s", buffer); | |
168 | } | |
1da177e4 LT |
169 | #endif |
170 | } | |
171 | ||
4996c023 TI |
172 | #ifdef CONFIG_KEXEC |
173 | static unsigned long acpi_rsdp; | |
174 | static int __init setup_acpi_rsdp(char *arg) | |
175 | { | |
5dcb9ca8 | 176 | return kstrtoul(arg, 16, &acpi_rsdp); |
4996c023 TI |
177 | } |
178 | early_param("acpi_rsdp", setup_acpi_rsdp); | |
179 | #endif | |
180 | ||
ad71860a | 181 | acpi_physical_address __init acpi_os_get_root_pointer(void) |
1da177e4 | 182 | { |
dfc9327a | 183 | acpi_physical_address pa; |
2fb65f09 | 184 | |
4996c023 | 185 | #ifdef CONFIG_KEXEC |
41fa1ee9 JB |
186 | /* |
187 | * We may have been provided with an RSDP on the command line, | |
188 | * but if a malicious user has done so they may be pointing us | |
189 | * at modified ACPI tables that could alter kernel behaviour - | |
190 | * so, we check the lockdown status before making use of | |
191 | * it. If we trust it then also stash it in an architecture | |
192 | * specific location (if appropriate) so it can be carried | |
193 | * over further kexec()s. | |
194 | */ | |
195 | if (acpi_rsdp && !security_locked_down(LOCKDOWN_ACPI_TABLES)) { | |
196 | acpi_arch_set_root_pointer(acpi_rsdp); | |
4996c023 | 197 | return acpi_rsdp; |
41fa1ee9 | 198 | } |
4996c023 | 199 | #endif |
dfc9327a JG |
200 | pa = acpi_arch_get_root_pointer(); |
201 | if (pa) | |
202 | return pa; | |
4996c023 | 203 | |
83e68189 | 204 | if (efi_enabled(EFI_CONFIG_TABLES)) { |
b2c99e3c | 205 | if (efi.acpi20 != EFI_INVALID_TABLE_ADDR) |
ad71860a | 206 | return efi.acpi20; |
2fb65f09 | 207 | if (efi.acpi != EFI_INVALID_TABLE_ADDR) |
ad71860a | 208 | return efi.acpi; |
2fb65f09 | 209 | pr_err(PREFIX "System description tables not found\n"); |
8a1664be | 210 | } else if (IS_ENABLED(CONFIG_ACPI_LEGACY_TABLES_LOOKUP)) { |
239665a3 | 211 | acpi_find_root_pointer(&pa); |
239665a3 | 212 | } |
8a1664be | 213 | |
2fb65f09 | 214 | return pa; |
1da177e4 LT |
215 | } |
216 | ||
78cdb3ed | 217 | /* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */ |
4a3cba5e MS |
218 | static struct acpi_ioremap * |
219 | acpi_map_lookup(acpi_physical_address phys, acpi_size size) | |
620242ae MS |
220 | { |
221 | struct acpi_ioremap *map; | |
222 | ||
bee6f871 | 223 | list_for_each_entry_rcu(map, &acpi_ioremaps, list, acpi_ioremap_lock_held()) |
620242ae MS |
224 | if (map->phys <= phys && |
225 | phys + size <= map->phys + map->size) | |
4a3cba5e MS |
226 | return map; |
227 | ||
228 | return NULL; | |
229 | } | |
230 | ||
231 | /* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */ | |
232 | static void __iomem * | |
233 | acpi_map_vaddr_lookup(acpi_physical_address phys, unsigned int size) | |
234 | { | |
235 | struct acpi_ioremap *map; | |
236 | ||
237 | map = acpi_map_lookup(phys, size); | |
238 | if (map) | |
239 | return map->virt + (phys - map->phys); | |
620242ae MS |
240 | |
241 | return NULL; | |
242 | } | |
243 | ||
13606a2d RW |
244 | void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size) |
245 | { | |
246 | struct acpi_ioremap *map; | |
247 | void __iomem *virt = NULL; | |
248 | ||
249 | mutex_lock(&acpi_ioremap_lock); | |
250 | map = acpi_map_lookup(phys, size); | |
251 | if (map) { | |
252 | virt = map->virt + (phys - map->phys); | |
253 | map->refcount++; | |
254 | } | |
255 | mutex_unlock(&acpi_ioremap_lock); | |
256 | return virt; | |
257 | } | |
258 | EXPORT_SYMBOL_GPL(acpi_os_get_iomem); | |
259 | ||
78cdb3ed | 260 | /* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */ |
620242ae MS |
261 | static struct acpi_ioremap * |
262 | acpi_map_lookup_virt(void __iomem *virt, acpi_size size) | |
263 | { | |
264 | struct acpi_ioremap *map; | |
265 | ||
bee6f871 | 266 | list_for_each_entry_rcu(map, &acpi_ioremaps, list, acpi_ioremap_lock_held()) |
4a3cba5e MS |
267 | if (map->virt <= virt && |
268 | virt + size <= map->virt + map->size) | |
620242ae MS |
269 | return map; |
270 | ||
271 | return NULL; | |
272 | } | |
273 | ||
aafc65c7 | 274 | #if defined(CONFIG_IA64) || defined(CONFIG_ARM64) |
ba242d5b MS |
275 | /* ioremap will take care of cache attributes */ |
276 | #define should_use_kmap(pfn) 0 | |
aafc65c7 GG |
277 | #else |
278 | #define should_use_kmap(pfn) page_is_ram(pfn) | |
ba242d5b MS |
279 | #endif |
280 | ||
281 | static void __iomem *acpi_map(acpi_physical_address pg_off, unsigned long pg_sz) | |
282 | { | |
283 | unsigned long pfn; | |
284 | ||
285 | pfn = pg_off >> PAGE_SHIFT; | |
286 | if (should_use_kmap(pfn)) { | |
287 | if (pg_sz > PAGE_SIZE) | |
288 | return NULL; | |
289 | return (void __iomem __force *)kmap(pfn_to_page(pfn)); | |
290 | } else | |
291 | return acpi_os_ioremap(pg_off, pg_sz); | |
292 | } | |
293 | ||
294 | static void acpi_unmap(acpi_physical_address pg_off, void __iomem *vaddr) | |
295 | { | |
296 | unsigned long pfn; | |
297 | ||
298 | pfn = pg_off >> PAGE_SHIFT; | |
e252675f | 299 | if (should_use_kmap(pfn)) |
ba242d5b MS |
300 | kunmap(pfn_to_page(pfn)); |
301 | else | |
302 | iounmap(vaddr); | |
303 | } | |
304 | ||
9d128ed1 RW |
305 | /** |
306 | * acpi_os_map_iomem - Get a virtual address for a given physical address range. | |
307 | * @phys: Start of the physical address range to map. | |
308 | * @size: Size of the physical address range to map. | |
309 | * | |
310 | * Look up the given physical address range in the list of existing ACPI memory | |
311 | * mappings. If found, get a reference to it and return a pointer to it (its | |
312 | * virtual address). If not found, map it, add it to that list and return a | |
313 | * pointer to it. | |
314 | * | |
8d3523fb | 315 | * During early init (when acpi_permanent_mmap has not been set yet) this |
9d128ed1 RW |
316 | * routine simply calls __acpi_map_table() to get the job done. |
317 | */ | |
9fe51603 QC |
318 | void __iomem __ref |
319 | *acpi_os_map_iomem(acpi_physical_address phys, acpi_size size) | |
1da177e4 | 320 | { |
7ffd0443 | 321 | struct acpi_ioremap *map; |
620242ae | 322 | void __iomem *virt; |
2d6d9fd3 RW |
323 | acpi_physical_address pg_off; |
324 | acpi_size pg_sz; | |
620242ae | 325 | |
9f4fd61f BH |
326 | if (phys > ULONG_MAX) { |
327 | printk(KERN_ERR PREFIX "Cannot map memory that high\n"); | |
70c0846e | 328 | return NULL; |
1da177e4 | 329 | } |
620242ae | 330 | |
8d3523fb | 331 | if (!acpi_permanent_mmap) |
ad71860a | 332 | return __acpi_map_table((unsigned long)phys, size); |
620242ae | 333 | |
7ffd0443 RW |
334 | mutex_lock(&acpi_ioremap_lock); |
335 | /* Check if there's a suitable mapping already. */ | |
336 | map = acpi_map_lookup(phys, size); | |
337 | if (map) { | |
b7c1fadd | 338 | map->refcount++; |
7ffd0443 RW |
339 | goto out; |
340 | } | |
341 | ||
620242ae | 342 | map = kzalloc(sizeof(*map), GFP_KERNEL); |
7ffd0443 RW |
343 | if (!map) { |
344 | mutex_unlock(&acpi_ioremap_lock); | |
620242ae | 345 | return NULL; |
7ffd0443 | 346 | } |
620242ae | 347 | |
4a3cba5e MS |
348 | pg_off = round_down(phys, PAGE_SIZE); |
349 | pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off; | |
ba242d5b | 350 | virt = acpi_map(pg_off, pg_sz); |
620242ae | 351 | if (!virt) { |
7ffd0443 | 352 | mutex_unlock(&acpi_ioremap_lock); |
620242ae MS |
353 | kfree(map); |
354 | return NULL; | |
355 | } | |
356 | ||
357 | INIT_LIST_HEAD(&map->list); | |
358 | map->virt = virt; | |
4a3cba5e MS |
359 | map->phys = pg_off; |
360 | map->size = pg_sz; | |
b7c1fadd | 361 | map->refcount = 1; |
620242ae | 362 | |
78cdb3ed | 363 | list_add_tail_rcu(&map->list, &acpi_ioremaps); |
620242ae | 364 | |
a238317c | 365 | out: |
7ffd0443 | 366 | mutex_unlock(&acpi_ioremap_lock); |
4a3cba5e | 367 | return map->virt + (phys - map->phys); |
1da177e4 | 368 | } |
a238317c LZ |
369 | EXPORT_SYMBOL_GPL(acpi_os_map_iomem); |
370 | ||
bd721ea7 | 371 | void *__ref acpi_os_map_memory(acpi_physical_address phys, acpi_size size) |
a238317c LZ |
372 | { |
373 | return (void *)acpi_os_map_iomem(phys, size); | |
374 | } | |
55a82ab3 | 375 | EXPORT_SYMBOL_GPL(acpi_os_map_memory); |
1da177e4 | 376 | |
833a426c FR |
377 | /* Must be called with mutex_lock(&acpi_ioremap_lock) */ |
378 | static unsigned long acpi_os_drop_map_ref(struct acpi_ioremap *map) | |
4a3cba5e | 379 | { |
833a426c FR |
380 | unsigned long refcount = --map->refcount; |
381 | ||
382 | if (!refcount) | |
b7c1fadd | 383 | list_del_rcu(&map->list); |
833a426c | 384 | return refcount; |
4a3cba5e | 385 | } |
4a3cba5e | 386 | |
b7c1fadd | 387 | static void acpi_os_map_cleanup(struct acpi_ioremap *map) |
7fe135dc | 388 | { |
833a426c FR |
389 | synchronize_rcu_expedited(); |
390 | acpi_unmap(map->phys, map->virt); | |
391 | kfree(map); | |
4a3cba5e MS |
392 | } |
393 | ||
9d128ed1 RW |
394 | /** |
395 | * acpi_os_unmap_iomem - Drop a memory mapping reference. | |
396 | * @virt: Start of the address range to drop a reference to. | |
397 | * @size: Size of the address range to drop a reference to. | |
398 | * | |
399 | * Look up the given virtual address range in the list of existing ACPI memory | |
400 | * mappings, drop a reference to it and unmap it if there are no more active | |
401 | * references to it. | |
402 | * | |
8d3523fb | 403 | * During early init (when acpi_permanent_mmap has not been set yet) this |
9d128ed1 RW |
404 | * routine simply calls __acpi_unmap_table() to get the job done. Since |
405 | * __acpi_unmap_table() is an __init function, the __ref annotation is needed | |
406 | * here. | |
407 | */ | |
a238317c | 408 | void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size) |
1da177e4 | 409 | { |
620242ae | 410 | struct acpi_ioremap *map; |
833a426c | 411 | unsigned long refcount; |
620242ae | 412 | |
8d3523fb | 413 | if (!acpi_permanent_mmap) { |
7d97277b | 414 | __acpi_unmap_table(virt, size); |
620242ae MS |
415 | return; |
416 | } | |
417 | ||
7bbb8903 | 418 | mutex_lock(&acpi_ioremap_lock); |
620242ae MS |
419 | map = acpi_map_lookup_virt(virt, size); |
420 | if (!map) { | |
7bbb8903 | 421 | mutex_unlock(&acpi_ioremap_lock); |
7fe135dc | 422 | WARN(true, PREFIX "%s: bad address %p\n", __func__, virt); |
620242ae MS |
423 | return; |
424 | } | |
833a426c | 425 | refcount = acpi_os_drop_map_ref(map); |
7bbb8903 | 426 | mutex_unlock(&acpi_ioremap_lock); |
620242ae | 427 | |
833a426c FR |
428 | if (!refcount) |
429 | acpi_os_map_cleanup(map); | |
1da177e4 | 430 | } |
a238317c LZ |
431 | EXPORT_SYMBOL_GPL(acpi_os_unmap_iomem); |
432 | ||
433 | void __ref acpi_os_unmap_memory(void *virt, acpi_size size) | |
434 | { | |
435 | return acpi_os_unmap_iomem((void __iomem *)virt, size); | |
436 | } | |
55a82ab3 | 437 | EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); |
1da177e4 | 438 | |
6f68c91c | 439 | int acpi_os_map_generic_address(struct acpi_generic_address *gas) |
29718521 | 440 | { |
bc9ffce2 | 441 | u64 addr; |
29718521 MS |
442 | void __iomem *virt; |
443 | ||
bc9ffce2 | 444 | if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) |
29718521 MS |
445 | return 0; |
446 | ||
bc9ffce2 MS |
447 | /* Handle possible alignment issues */ |
448 | memcpy(&addr, &gas->address, sizeof(addr)); | |
449 | if (!addr || !gas->bit_width) | |
29718521 MS |
450 | return -EINVAL; |
451 | ||
a238317c | 452 | virt = acpi_os_map_iomem(addr, gas->bit_width / 8); |
29718521 MS |
453 | if (!virt) |
454 | return -EIO; | |
455 | ||
456 | return 0; | |
457 | } | |
6f68c91c | 458 | EXPORT_SYMBOL(acpi_os_map_generic_address); |
29718521 | 459 | |
6f68c91c | 460 | void acpi_os_unmap_generic_address(struct acpi_generic_address *gas) |
29718521 | 461 | { |
bc9ffce2 | 462 | u64 addr; |
7fe135dc | 463 | struct acpi_ioremap *map; |
833a426c | 464 | unsigned long refcount; |
29718521 | 465 | |
bc9ffce2 | 466 | if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) |
29718521 MS |
467 | return; |
468 | ||
bc9ffce2 MS |
469 | /* Handle possible alignment issues */ |
470 | memcpy(&addr, &gas->address, sizeof(addr)); | |
471 | if (!addr || !gas->bit_width) | |
29718521 MS |
472 | return; |
473 | ||
7bbb8903 | 474 | mutex_lock(&acpi_ioremap_lock); |
bc9ffce2 | 475 | map = acpi_map_lookup(addr, gas->bit_width / 8); |
7fe135dc RW |
476 | if (!map) { |
477 | mutex_unlock(&acpi_ioremap_lock); | |
478 | return; | |
479 | } | |
833a426c | 480 | refcount = acpi_os_drop_map_ref(map); |
7bbb8903 | 481 | mutex_unlock(&acpi_ioremap_lock); |
29718521 | 482 | |
833a426c FR |
483 | if (!refcount) |
484 | acpi_os_map_cleanup(map); | |
29718521 | 485 | } |
6f68c91c | 486 | EXPORT_SYMBOL(acpi_os_unmap_generic_address); |
29718521 | 487 | |
1da177e4 LT |
488 | #ifdef ACPI_FUTURE_USAGE |
489 | acpi_status | |
4be44fcd | 490 | acpi_os_get_physical_address(void *virt, acpi_physical_address * phys) |
1da177e4 | 491 | { |
4be44fcd | 492 | if (!phys || !virt) |
1da177e4 LT |
493 | return AE_BAD_PARAMETER; |
494 | ||
495 | *phys = virt_to_phys(virt); | |
496 | ||
497 | return AE_OK; | |
498 | } | |
499 | #endif | |
500 | ||
18d78b64 RW |
501 | #ifdef CONFIG_ACPI_REV_OVERRIDE_POSSIBLE |
502 | static bool acpi_rev_override; | |
503 | ||
504 | int __init acpi_rev_override_setup(char *str) | |
505 | { | |
506 | acpi_rev_override = true; | |
507 | return 1; | |
508 | } | |
509 | __setup("acpi_rev_override", acpi_rev_override_setup); | |
510 | #else | |
511 | #define acpi_rev_override false | |
512 | #endif | |
513 | ||
1da177e4 LT |
514 | #define ACPI_MAX_OVERRIDE_LEN 100 |
515 | ||
516 | static char acpi_os_name[ACPI_MAX_OVERRIDE_LEN]; | |
517 | ||
518 | acpi_status | |
4be44fcd | 519 | acpi_os_predefined_override(const struct acpi_predefined_names *init_val, |
80b28810 | 520 | acpi_string *new_val) |
1da177e4 LT |
521 | { |
522 | if (!init_val || !new_val) | |
523 | return AE_BAD_PARAMETER; | |
524 | ||
525 | *new_val = NULL; | |
4be44fcd | 526 | if (!memcmp(init_val->name, "_OS_", 4) && strlen(acpi_os_name)) { |
1da177e4 | 527 | printk(KERN_INFO PREFIX "Overriding _OS definition to '%s'\n", |
4be44fcd | 528 | acpi_os_name); |
1da177e4 LT |
529 | *new_val = acpi_os_name; |
530 | } | |
531 | ||
18d78b64 RW |
532 | if (!memcmp(init_val->name, "_REV", 4) && acpi_rev_override) { |
533 | printk(KERN_INFO PREFIX "Overriding _REV return value to 5\n"); | |
534 | *new_val = (char *)5; | |
535 | } | |
536 | ||
1da177e4 LT |
537 | return AE_OK; |
538 | } | |
539 | ||
7d12e780 | 540 | static irqreturn_t acpi_irq(int irq, void *dev_id) |
1da177e4 | 541 | { |
5229e87d LB |
542 | u32 handled; |
543 | ||
544 | handled = (*acpi_irq_handler) (acpi_irq_context); | |
545 | ||
546 | if (handled) { | |
547 | acpi_irq_handled++; | |
548 | return IRQ_HANDLED; | |
88bea188 LB |
549 | } else { |
550 | acpi_irq_not_handled++; | |
5229e87d | 551 | return IRQ_NONE; |
88bea188 | 552 | } |
1da177e4 LT |
553 | } |
554 | ||
555 | acpi_status | |
4be44fcd LB |
556 | acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, |
557 | void *context) | |
1da177e4 LT |
558 | { |
559 | unsigned int irq; | |
560 | ||
5229e87d LB |
561 | acpi_irq_stats_init(); |
562 | ||
1da177e4 | 563 | /* |
23fe3630 RW |
564 | * ACPI interrupts different from the SCI in our copy of the FADT are |
565 | * not supported. | |
1da177e4 | 566 | */ |
23fe3630 RW |
567 | if (gsi != acpi_gbl_FADT.sci_interrupt) |
568 | return AE_BAD_PARAMETER; | |
569 | ||
570 | if (acpi_irq_handler) | |
571 | return AE_ALREADY_ACQUIRED; | |
572 | ||
1da177e4 LT |
573 | if (acpi_gsi_to_irq(gsi, &irq) < 0) { |
574 | printk(KERN_ERR PREFIX "SCI (ACPI GSI %d) not registered\n", | |
575 | gsi); | |
576 | return AE_OK; | |
577 | } | |
578 | ||
579 | acpi_irq_handler = handler; | |
580 | acpi_irq_context = context; | |
a8d46b9e | 581 | if (request_irq(irq, acpi_irq, IRQF_SHARED, "acpi", acpi_irq)) { |
1da177e4 | 582 | printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq); |
23fe3630 | 583 | acpi_irq_handler = NULL; |
1da177e4 LT |
584 | return AE_NOT_ACQUIRED; |
585 | } | |
49e4b843 | 586 | acpi_sci_irq = irq; |
1da177e4 LT |
587 | |
588 | return AE_OK; | |
589 | } | |
590 | ||
49e4b843 | 591 | acpi_status acpi_os_remove_interrupt_handler(u32 gsi, acpi_osd_handler handler) |
1da177e4 | 592 | { |
49e4b843 | 593 | if (gsi != acpi_gbl_FADT.sci_interrupt || !acpi_sci_irq_valid()) |
23fe3630 RW |
594 | return AE_BAD_PARAMETER; |
595 | ||
49e4b843 | 596 | free_irq(acpi_sci_irq, acpi_irq); |
23fe3630 | 597 | acpi_irq_handler = NULL; |
49e4b843 | 598 | acpi_sci_irq = INVALID_ACPI_IRQ; |
1da177e4 LT |
599 | |
600 | return AE_OK; | |
601 | } | |
602 | ||
603 | /* | |
604 | * Running in interpreter thread context, safe to sleep | |
605 | */ | |
606 | ||
439913ff | 607 | void acpi_os_sleep(u64 ms) |
1da177e4 | 608 | { |
30282299 | 609 | msleep(ms); |
1da177e4 | 610 | } |
4be44fcd | 611 | |
4be44fcd | 612 | void acpi_os_stall(u32 us) |
1da177e4 LT |
613 | { |
614 | while (us) { | |
615 | u32 delay = 1000; | |
616 | ||
617 | if (delay > us) | |
618 | delay = us; | |
619 | udelay(delay); | |
620 | touch_nmi_watchdog(); | |
621 | us -= delay; | |
622 | } | |
623 | } | |
4be44fcd | 624 | |
1da177e4 | 625 | /* |
83b2348e BVA |
626 | * Support ACPI 3.0 AML Timer operand. Returns a 64-bit free-running, |
627 | * monotonically increasing timer with 100ns granularity. Do not use | |
628 | * ktime_get() to implement this function because this function may get | |
629 | * called after timekeeping has been suspended. Note: calling this function | |
630 | * after timekeeping has been suspended may lead to unexpected results | |
631 | * because when timekeeping is suspended the jiffies counter is not | |
632 | * incremented. See also timekeeping_suspend(). | |
1da177e4 | 633 | */ |
4be44fcd | 634 | u64 acpi_os_get_timer(void) |
1da177e4 | 635 | { |
83b2348e BVA |
636 | return (get_jiffies_64() - INITIAL_JIFFIES) * |
637 | (ACPI_100NSEC_PER_SEC / HZ); | |
1da177e4 LT |
638 | } |
639 | ||
4be44fcd | 640 | acpi_status acpi_os_read_port(acpi_io_address port, u32 * value, u32 width) |
1da177e4 LT |
641 | { |
642 | u32 dummy; | |
643 | ||
644 | if (!value) | |
645 | value = &dummy; | |
646 | ||
49fbabf5 ZY |
647 | *value = 0; |
648 | if (width <= 8) { | |
4be44fcd | 649 | *(u8 *) value = inb(port); |
49fbabf5 | 650 | } else if (width <= 16) { |
4be44fcd | 651 | *(u16 *) value = inw(port); |
49fbabf5 | 652 | } else if (width <= 32) { |
4be44fcd | 653 | *(u32 *) value = inl(port); |
49fbabf5 | 654 | } else { |
1da177e4 LT |
655 | BUG(); |
656 | } | |
657 | ||
658 | return AE_OK; | |
659 | } | |
4be44fcd | 660 | |
1da177e4 LT |
661 | EXPORT_SYMBOL(acpi_os_read_port); |
662 | ||
4be44fcd | 663 | acpi_status acpi_os_write_port(acpi_io_address port, u32 value, u32 width) |
1da177e4 | 664 | { |
49fbabf5 | 665 | if (width <= 8) { |
1da177e4 | 666 | outb(value, port); |
49fbabf5 | 667 | } else if (width <= 16) { |
1da177e4 | 668 | outw(value, port); |
49fbabf5 | 669 | } else if (width <= 32) { |
1da177e4 | 670 | outl(value, port); |
49fbabf5 | 671 | } else { |
1da177e4 LT |
672 | BUG(); |
673 | } | |
674 | ||
675 | return AE_OK; | |
676 | } | |
4be44fcd | 677 | |
1da177e4 LT |
678 | EXPORT_SYMBOL(acpi_os_write_port); |
679 | ||
eeb2d80d SP |
680 | int acpi_os_read_iomem(void __iomem *virt_addr, u64 *value, u32 width) |
681 | { | |
682 | ||
683 | switch (width) { | |
684 | case 8: | |
685 | *(u8 *) value = readb(virt_addr); | |
686 | break; | |
687 | case 16: | |
688 | *(u16 *) value = readw(virt_addr); | |
689 | break; | |
690 | case 32: | |
691 | *(u32 *) value = readl(virt_addr); | |
692 | break; | |
693 | case 64: | |
694 | *(u64 *) value = readq(virt_addr); | |
695 | break; | |
696 | default: | |
697 | return -EINVAL; | |
698 | } | |
699 | ||
700 | return 0; | |
701 | } | |
702 | ||
e615bf5b | 703 | acpi_status |
653f4b53 | 704 | acpi_os_read_memory(acpi_physical_address phys_addr, u64 *value, u32 width) |
e615bf5b MS |
705 | { |
706 | void __iomem *virt_addr; | |
707 | unsigned int size = width / 8; | |
708 | bool unmap = false; | |
709 | u64 dummy; | |
eeb2d80d | 710 | int error; |
e615bf5b MS |
711 | |
712 | rcu_read_lock(); | |
713 | virt_addr = acpi_map_vaddr_lookup(phys_addr, size); | |
714 | if (!virt_addr) { | |
715 | rcu_read_unlock(); | |
716 | virt_addr = acpi_os_ioremap(phys_addr, size); | |
717 | if (!virt_addr) | |
718 | return AE_BAD_ADDRESS; | |
719 | unmap = true; | |
720 | } | |
721 | ||
722 | if (!value) | |
723 | value = &dummy; | |
724 | ||
eeb2d80d SP |
725 | error = acpi_os_read_iomem(virt_addr, value, width); |
726 | BUG_ON(error); | |
e615bf5b MS |
727 | |
728 | if (unmap) | |
729 | iounmap(virt_addr); | |
730 | else | |
731 | rcu_read_unlock(); | |
732 | ||
733 | return AE_OK; | |
734 | } | |
735 | ||
e615bf5b | 736 | acpi_status |
653f4b53 | 737 | acpi_os_write_memory(acpi_physical_address phys_addr, u64 value, u32 width) |
e615bf5b MS |
738 | { |
739 | void __iomem *virt_addr; | |
740 | unsigned int size = width / 8; | |
741 | bool unmap = false; | |
742 | ||
743 | rcu_read_lock(); | |
744 | virt_addr = acpi_map_vaddr_lookup(phys_addr, size); | |
745 | if (!virt_addr) { | |
746 | rcu_read_unlock(); | |
747 | virt_addr = acpi_os_ioremap(phys_addr, size); | |
748 | if (!virt_addr) | |
749 | return AE_BAD_ADDRESS; | |
750 | unmap = true; | |
751 | } | |
752 | ||
753 | switch (width) { | |
754 | case 8: | |
755 | writeb(value, virt_addr); | |
756 | break; | |
757 | case 16: | |
758 | writew(value, virt_addr); | |
759 | break; | |
760 | case 32: | |
761 | writel(value, virt_addr); | |
762 | break; | |
763 | case 64: | |
3277b4ea | 764 | writeq(value, virt_addr); |
e615bf5b MS |
765 | break; |
766 | default: | |
767 | BUG(); | |
768 | } | |
769 | ||
770 | if (unmap) | |
771 | iounmap(virt_addr); | |
772 | else | |
773 | rcu_read_unlock(); | |
774 | ||
775 | return AE_OK; | |
776 | } | |
777 | ||
bd23fac3 | 778 | #ifdef CONFIG_PCI |
1da177e4 | 779 | acpi_status |
4be44fcd | 780 | acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, |
c5f0231e | 781 | u64 *value, u32 width) |
1da177e4 LT |
782 | { |
783 | int result, size; | |
c5f0231e | 784 | u32 value32; |
1da177e4 LT |
785 | |
786 | if (!value) | |
787 | return AE_BAD_PARAMETER; | |
788 | ||
789 | switch (width) { | |
790 | case 8: | |
791 | size = 1; | |
792 | break; | |
793 | case 16: | |
794 | size = 2; | |
795 | break; | |
796 | case 32: | |
797 | size = 4; | |
798 | break; | |
799 | default: | |
800 | return AE_ERROR; | |
801 | } | |
802 | ||
b6ce068a MW |
803 | result = raw_pci_read(pci_id->segment, pci_id->bus, |
804 | PCI_DEVFN(pci_id->device, pci_id->function), | |
c5f0231e BM |
805 | reg, size, &value32); |
806 | *value = value32; | |
1da177e4 LT |
807 | |
808 | return (result ? AE_ERROR : AE_OK); | |
809 | } | |
4be44fcd | 810 | |
1da177e4 | 811 | acpi_status |
4be44fcd | 812 | acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, |
439913ff | 813 | u64 value, u32 width) |
1da177e4 LT |
814 | { |
815 | int result, size; | |
816 | ||
817 | switch (width) { | |
818 | case 8: | |
819 | size = 1; | |
820 | break; | |
821 | case 16: | |
822 | size = 2; | |
823 | break; | |
824 | case 32: | |
825 | size = 4; | |
826 | break; | |
827 | default: | |
828 | return AE_ERROR; | |
829 | } | |
830 | ||
b6ce068a MW |
831 | result = raw_pci_write(pci_id->segment, pci_id->bus, |
832 | PCI_DEVFN(pci_id->device, pci_id->function), | |
833 | reg, size, value); | |
1da177e4 LT |
834 | |
835 | return (result ? AE_ERROR : AE_OK); | |
836 | } | |
bd23fac3 | 837 | #endif |
1da177e4 | 838 | |
65f27f38 | 839 | static void acpi_os_execute_deferred(struct work_struct *work) |
88db5e14 AS |
840 | { |
841 | struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); | |
88db5e14 | 842 | |
19cd847a ZR |
843 | dpc->function(dpc->context); |
844 | kfree(dpc); | |
19cd847a ZR |
845 | } |
846 | ||
836d0830 LZ |
847 | #ifdef CONFIG_ACPI_DEBUGGER |
848 | static struct acpi_debugger acpi_debugger; | |
849 | static bool acpi_debugger_initialized; | |
850 | ||
851 | int acpi_register_debugger(struct module *owner, | |
852 | const struct acpi_debugger_ops *ops) | |
853 | { | |
854 | int ret = 0; | |
855 | ||
856 | mutex_lock(&acpi_debugger.lock); | |
857 | if (acpi_debugger.ops) { | |
858 | ret = -EBUSY; | |
859 | goto err_lock; | |
860 | } | |
861 | ||
862 | acpi_debugger.owner = owner; | |
863 | acpi_debugger.ops = ops; | |
864 | ||
865 | err_lock: | |
866 | mutex_unlock(&acpi_debugger.lock); | |
867 | return ret; | |
868 | } | |
869 | EXPORT_SYMBOL(acpi_register_debugger); | |
870 | ||
871 | void acpi_unregister_debugger(const struct acpi_debugger_ops *ops) | |
872 | { | |
873 | mutex_lock(&acpi_debugger.lock); | |
874 | if (ops == acpi_debugger.ops) { | |
875 | acpi_debugger.ops = NULL; | |
876 | acpi_debugger.owner = NULL; | |
877 | } | |
878 | mutex_unlock(&acpi_debugger.lock); | |
879 | } | |
880 | EXPORT_SYMBOL(acpi_unregister_debugger); | |
881 | ||
882 | int acpi_debugger_create_thread(acpi_osd_exec_callback function, void *context) | |
883 | { | |
884 | int ret; | |
885 | int (*func)(acpi_osd_exec_callback, void *); | |
886 | struct module *owner; | |
887 | ||
888 | if (!acpi_debugger_initialized) | |
889 | return -ENODEV; | |
890 | mutex_lock(&acpi_debugger.lock); | |
891 | if (!acpi_debugger.ops) { | |
892 | ret = -ENODEV; | |
893 | goto err_lock; | |
894 | } | |
895 | if (!try_module_get(acpi_debugger.owner)) { | |
896 | ret = -ENODEV; | |
897 | goto err_lock; | |
898 | } | |
899 | func = acpi_debugger.ops->create_thread; | |
900 | owner = acpi_debugger.owner; | |
901 | mutex_unlock(&acpi_debugger.lock); | |
902 | ||
903 | ret = func(function, context); | |
904 | ||
905 | mutex_lock(&acpi_debugger.lock); | |
906 | module_put(owner); | |
907 | err_lock: | |
908 | mutex_unlock(&acpi_debugger.lock); | |
909 | return ret; | |
910 | } | |
911 | ||
912 | ssize_t acpi_debugger_write_log(const char *msg) | |
913 | { | |
914 | ssize_t ret; | |
915 | ssize_t (*func)(const char *); | |
916 | struct module *owner; | |
917 | ||
918 | if (!acpi_debugger_initialized) | |
919 | return -ENODEV; | |
920 | mutex_lock(&acpi_debugger.lock); | |
921 | if (!acpi_debugger.ops) { | |
922 | ret = -ENODEV; | |
923 | goto err_lock; | |
924 | } | |
925 | if (!try_module_get(acpi_debugger.owner)) { | |
926 | ret = -ENODEV; | |
927 | goto err_lock; | |
928 | } | |
929 | func = acpi_debugger.ops->write_log; | |
930 | owner = acpi_debugger.owner; | |
931 | mutex_unlock(&acpi_debugger.lock); | |
932 | ||
933 | ret = func(msg); | |
934 | ||
935 | mutex_lock(&acpi_debugger.lock); | |
936 | module_put(owner); | |
937 | err_lock: | |
938 | mutex_unlock(&acpi_debugger.lock); | |
939 | return ret; | |
940 | } | |
941 | ||
942 | ssize_t acpi_debugger_read_cmd(char *buffer, size_t buffer_length) | |
943 | { | |
944 | ssize_t ret; | |
945 | ssize_t (*func)(char *, size_t); | |
946 | struct module *owner; | |
947 | ||
948 | if (!acpi_debugger_initialized) | |
949 | return -ENODEV; | |
950 | mutex_lock(&acpi_debugger.lock); | |
951 | if (!acpi_debugger.ops) { | |
952 | ret = -ENODEV; | |
953 | goto err_lock; | |
954 | } | |
955 | if (!try_module_get(acpi_debugger.owner)) { | |
956 | ret = -ENODEV; | |
957 | goto err_lock; | |
958 | } | |
959 | func = acpi_debugger.ops->read_cmd; | |
960 | owner = acpi_debugger.owner; | |
961 | mutex_unlock(&acpi_debugger.lock); | |
962 | ||
963 | ret = func(buffer, buffer_length); | |
964 | ||
965 | mutex_lock(&acpi_debugger.lock); | |
966 | module_put(owner); | |
967 | err_lock: | |
968 | mutex_unlock(&acpi_debugger.lock); | |
969 | return ret; | |
970 | } | |
971 | ||
972 | int acpi_debugger_wait_command_ready(void) | |
973 | { | |
974 | int ret; | |
975 | int (*func)(bool, char *, size_t); | |
976 | struct module *owner; | |
977 | ||
978 | if (!acpi_debugger_initialized) | |
979 | return -ENODEV; | |
980 | mutex_lock(&acpi_debugger.lock); | |
981 | if (!acpi_debugger.ops) { | |
982 | ret = -ENODEV; | |
983 | goto err_lock; | |
984 | } | |
985 | if (!try_module_get(acpi_debugger.owner)) { | |
986 | ret = -ENODEV; | |
987 | goto err_lock; | |
988 | } | |
989 | func = acpi_debugger.ops->wait_command_ready; | |
990 | owner = acpi_debugger.owner; | |
991 | mutex_unlock(&acpi_debugger.lock); | |
992 | ||
993 | ret = func(acpi_gbl_method_executing, | |
994 | acpi_gbl_db_line_buf, ACPI_DB_LINE_BUFFER_SIZE); | |
995 | ||
996 | mutex_lock(&acpi_debugger.lock); | |
997 | module_put(owner); | |
998 | err_lock: | |
999 | mutex_unlock(&acpi_debugger.lock); | |
1000 | return ret; | |
1001 | } | |
1002 | ||
1003 | int acpi_debugger_notify_command_complete(void) | |
1004 | { | |
1005 | int ret; | |
1006 | int (*func)(void); | |
1007 | struct module *owner; | |
1008 | ||
1009 | if (!acpi_debugger_initialized) | |
1010 | return -ENODEV; | |
1011 | mutex_lock(&acpi_debugger.lock); | |
1012 | if (!acpi_debugger.ops) { | |
1013 | ret = -ENODEV; | |
1014 | goto err_lock; | |
1015 | } | |
1016 | if (!try_module_get(acpi_debugger.owner)) { | |
1017 | ret = -ENODEV; | |
1018 | goto err_lock; | |
1019 | } | |
1020 | func = acpi_debugger.ops->notify_command_complete; | |
1021 | owner = acpi_debugger.owner; | |
1022 | mutex_unlock(&acpi_debugger.lock); | |
1023 | ||
1024 | ret = func(); | |
1025 | ||
1026 | mutex_lock(&acpi_debugger.lock); | |
1027 | module_put(owner); | |
1028 | err_lock: | |
1029 | mutex_unlock(&acpi_debugger.lock); | |
1030 | return ret; | |
1031 | } | |
1032 | ||
1033 | int __init acpi_debugger_init(void) | |
1034 | { | |
1035 | mutex_init(&acpi_debugger.lock); | |
1036 | acpi_debugger_initialized = true; | |
1037 | return 0; | |
1038 | } | |
1039 | #endif | |
1040 | ||
b8d35192 AS |
1041 | /******************************************************************************* |
1042 | * | |
1043 | * FUNCTION: acpi_os_execute | |
1044 | * | |
1045 | * PARAMETERS: Type - Type of the callback | |
1046 | * Function - Function to be executed | |
1047 | * Context - Function parameters | |
1048 | * | |
1049 | * RETURN: Status | |
1050 | * | |
1051 | * DESCRIPTION: Depending on type, either queues function for deferred execution or | |
1052 | * immediately executes function on a separate thread. | |
1053 | * | |
1054 | ******************************************************************************/ | |
1055 | ||
7b98118a RW |
1056 | acpi_status acpi_os_execute(acpi_execute_type type, |
1057 | acpi_osd_exec_callback function, void *context) | |
1da177e4 | 1058 | { |
4be44fcd LB |
1059 | acpi_status status = AE_OK; |
1060 | struct acpi_os_dpc *dpc; | |
17bc54ee | 1061 | struct workqueue_struct *queue; |
19cd847a | 1062 | int ret; |
72945b2b LB |
1063 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
1064 | "Scheduling function [%p(%p)] for deferred execution.\n", | |
1065 | function, context)); | |
1da177e4 | 1066 | |
8cfb0cdf | 1067 | if (type == OSL_DEBUGGER_MAIN_THREAD) { |
836d0830 | 1068 | ret = acpi_debugger_create_thread(function, context); |
8cfb0cdf LZ |
1069 | if (ret) { |
1070 | pr_err("Call to kthread_create() failed.\n"); | |
1071 | status = AE_ERROR; | |
1072 | } | |
1073 | goto out_thread; | |
1074 | } | |
1075 | ||
1da177e4 LT |
1076 | /* |
1077 | * Allocate/initialize DPC structure. Note that this memory will be | |
65f27f38 | 1078 | * freed by the callee. The kernel handles the work_struct list in a |
1da177e4 LT |
1079 | * way that allows us to also free its memory inside the callee. |
1080 | * Because we may want to schedule several tasks with different | |
1081 | * parameters we can't use the approach some kernel code uses of | |
65f27f38 | 1082 | * having a static work_struct. |
1da177e4 | 1083 | */ |
72945b2b | 1084 | |
3ae45a27 | 1085 | dpc = kzalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC); |
1da177e4 | 1086 | if (!dpc) |
889c78be | 1087 | return AE_NO_MEMORY; |
b976fe19 | 1088 | |
1da177e4 LT |
1089 | dpc->function = function; |
1090 | dpc->context = context; | |
b976fe19 | 1091 | |
c02256be | 1092 | /* |
3ae45a27 RW |
1093 | * To prevent lockdep from complaining unnecessarily, make sure that |
1094 | * there is a different static lockdep key for each workqueue by using | |
1095 | * INIT_WORK() for each of them separately. | |
c02256be | 1096 | */ |
7b98118a | 1097 | if (type == OSL_NOTIFY_HANDLER) { |
3ae45a27 | 1098 | queue = kacpi_notify_wq; |
bc73675b | 1099 | INIT_WORK(&dpc->work, acpi_os_execute_deferred); |
8cfb0cdf | 1100 | } else if (type == OSL_GPE_HANDLER) { |
3ae45a27 | 1101 | queue = kacpid_wq; |
bc73675b | 1102 | INIT_WORK(&dpc->work, acpi_os_execute_deferred); |
8cfb0cdf LZ |
1103 | } else { |
1104 | pr_err("Unsupported os_execute type %d.\n", type); | |
1105 | status = AE_ERROR; | |
3ae45a27 | 1106 | } |
bc73675b | 1107 | |
8cfb0cdf LZ |
1108 | if (ACPI_FAILURE(status)) |
1109 | goto err_workqueue; | |
1110 | ||
8fec62b2 TH |
1111 | /* |
1112 | * On some machines, a software-initiated SMI causes corruption unless | |
1113 | * the SMI runs on CPU 0. An SMI can be initiated by any AML, but | |
1114 | * typically it's done in GPE-related methods that are run via | |
1115 | * workqueues, so we can avoid the known corruption cases by always | |
1116 | * queueing on CPU 0. | |
1117 | */ | |
1118 | ret = queue_work_on(0, queue, &dpc->work); | |
19cd847a | 1119 | if (!ret) { |
55ac9a01 LM |
1120 | printk(KERN_ERR PREFIX |
1121 | "Call to queue_work() failed.\n"); | |
17bc54ee | 1122 | status = AE_ERROR; |
1da177e4 | 1123 | } |
8cfb0cdf LZ |
1124 | err_workqueue: |
1125 | if (ACPI_FAILURE(status)) | |
1126 | kfree(dpc); | |
1127 | out_thread: | |
889c78be | 1128 | return status; |
1da177e4 | 1129 | } |
7b98118a | 1130 | EXPORT_SYMBOL(acpi_os_execute); |
4be44fcd | 1131 | |
7b98118a | 1132 | void acpi_os_wait_events_complete(void) |
19cd847a | 1133 | { |
90253a79 LZ |
1134 | /* |
1135 | * Make sure the GPE handler or the fixed event handler is not used | |
1136 | * on another CPU after removal. | |
1137 | */ | |
efb1cf7d CY |
1138 | if (acpi_sci_irq_valid()) |
1139 | synchronize_hardirq(acpi_sci_irq); | |
7b98118a RW |
1140 | flush_workqueue(kacpid_wq); |
1141 | flush_workqueue(kacpi_notify_wq); | |
19cd847a | 1142 | } |
757c968c | 1143 | EXPORT_SYMBOL(acpi_os_wait_events_complete); |
1da177e4 | 1144 | |
7b98118a RW |
1145 | struct acpi_hp_work { |
1146 | struct work_struct work; | |
1e3bcb59 | 1147 | struct acpi_device *adev; |
7b98118a RW |
1148 | u32 src; |
1149 | }; | |
1150 | ||
1151 | static void acpi_hotplug_work_fn(struct work_struct *work) | |
19cd847a | 1152 | { |
7b98118a RW |
1153 | struct acpi_hp_work *hpw = container_of(work, struct acpi_hp_work, work); |
1154 | ||
1155 | acpi_os_wait_events_complete(); | |
1e3bcb59 | 1156 | acpi_device_hotplug(hpw->adev, hpw->src); |
7b98118a | 1157 | kfree(hpw); |
19cd847a ZR |
1158 | } |
1159 | ||
1e3bcb59 | 1160 | acpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src) |
1da177e4 | 1161 | { |
7b98118a RW |
1162 | struct acpi_hp_work *hpw; |
1163 | ||
1164 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, | |
1e3bcb59 RW |
1165 | "Scheduling hotplug event (%p, %u) for deferred execution.\n", |
1166 | adev, src)); | |
7b98118a RW |
1167 | |
1168 | hpw = kmalloc(sizeof(*hpw), GFP_KERNEL); | |
1169 | if (!hpw) | |
1170 | return AE_NO_MEMORY; | |
1171 | ||
1172 | INIT_WORK(&hpw->work, acpi_hotplug_work_fn); | |
1e3bcb59 | 1173 | hpw->adev = adev; |
7b98118a RW |
1174 | hpw->src = src; |
1175 | /* | |
1176 | * We can't run hotplug code in kacpid_wq/kacpid_notify_wq etc., because | |
1177 | * the hotplug code may call driver .remove() functions, which may | |
1178 | * invoke flush_scheduled_work()/acpi_os_wait_events_complete() to flush | |
1179 | * these workqueues. | |
1180 | */ | |
1181 | if (!queue_work(kacpi_hotplug_wq, &hpw->work)) { | |
1182 | kfree(hpw); | |
1183 | return AE_ERROR; | |
1184 | } | |
1185 | return AE_OK; | |
1da177e4 | 1186 | } |
4be44fcd | 1187 | |
d783156e RW |
1188 | bool acpi_queue_hotplug_work(struct work_struct *work) |
1189 | { | |
1190 | return queue_work(kacpi_hotplug_wq, work); | |
1191 | } | |
1da177e4 | 1192 | |
1da177e4 | 1193 | acpi_status |
4be44fcd | 1194 | acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle) |
1da177e4 | 1195 | { |
4be44fcd | 1196 | struct semaphore *sem = NULL; |
1da177e4 | 1197 | |
2d0acb4a | 1198 | sem = acpi_os_allocate_zeroed(sizeof(struct semaphore)); |
1da177e4 | 1199 | if (!sem) |
d550d98d | 1200 | return AE_NO_MEMORY; |
1da177e4 LT |
1201 | |
1202 | sema_init(sem, initial_units); | |
1203 | ||
4be44fcd | 1204 | *handle = (acpi_handle *) sem; |
1da177e4 | 1205 | |
4be44fcd LB |
1206 | ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Creating semaphore[%p|%d].\n", |
1207 | *handle, initial_units)); | |
1da177e4 | 1208 | |
d550d98d | 1209 | return AE_OK; |
1da177e4 | 1210 | } |
1da177e4 | 1211 | |
1da177e4 LT |
1212 | /* |
1213 | * TODO: A better way to delete semaphores? Linux doesn't have a | |
1214 | * 'delete_semaphore()' function -- may result in an invalid | |
1215 | * pointer dereference for non-synchronized consumers. Should | |
1216 | * we at least check for blocked threads and signal/cancel them? | |
1217 | */ | |
1218 | ||
4be44fcd | 1219 | acpi_status acpi_os_delete_semaphore(acpi_handle handle) |
1da177e4 | 1220 | { |
4be44fcd | 1221 | struct semaphore *sem = (struct semaphore *)handle; |
1da177e4 | 1222 | |
1da177e4 | 1223 | if (!sem) |
d550d98d | 1224 | return AE_BAD_PARAMETER; |
1da177e4 | 1225 | |
4be44fcd | 1226 | ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Deleting semaphore[%p].\n", handle)); |
1da177e4 | 1227 | |
f1241c87 | 1228 | BUG_ON(!list_empty(&sem->wait_list)); |
02438d87 | 1229 | kfree(sem); |
4be44fcd | 1230 | sem = NULL; |
1da177e4 | 1231 | |
d550d98d | 1232 | return AE_OK; |
1da177e4 | 1233 | } |
1da177e4 | 1234 | |
1da177e4 | 1235 | /* |
1da177e4 LT |
1236 | * TODO: Support for units > 1? |
1237 | */ | |
4be44fcd | 1238 | acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout) |
1da177e4 | 1239 | { |
4be44fcd LB |
1240 | acpi_status status = AE_OK; |
1241 | struct semaphore *sem = (struct semaphore *)handle; | |
f1241c87 | 1242 | long jiffies; |
4be44fcd | 1243 | int ret = 0; |
1da177e4 | 1244 | |
7901a052 LZ |
1245 | if (!acpi_os_initialized) |
1246 | return AE_OK; | |
1247 | ||
1da177e4 | 1248 | if (!sem || (units < 1)) |
d550d98d | 1249 | return AE_BAD_PARAMETER; |
1da177e4 LT |
1250 | |
1251 | if (units > 1) | |
d550d98d | 1252 | return AE_SUPPORT; |
1da177e4 | 1253 | |
4be44fcd LB |
1254 | ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Waiting for semaphore[%p|%d|%d]\n", |
1255 | handle, units, timeout)); | |
1da177e4 | 1256 | |
f1241c87 MW |
1257 | if (timeout == ACPI_WAIT_FOREVER) |
1258 | jiffies = MAX_SCHEDULE_TIMEOUT; | |
1259 | else | |
1260 | jiffies = msecs_to_jiffies(timeout); | |
cad1525a | 1261 | |
f1241c87 MW |
1262 | ret = down_timeout(sem, jiffies); |
1263 | if (ret) | |
1264 | status = AE_TIME; | |
1da177e4 LT |
1265 | |
1266 | if (ACPI_FAILURE(status)) { | |
9e7e2c04 | 1267 | ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, |
a6fc6720 | 1268 | "Failed to acquire semaphore[%p|%d|%d], %s", |
4be44fcd LB |
1269 | handle, units, timeout, |
1270 | acpi_format_exception(status))); | |
1271 | } else { | |
1272 | ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, | |
a6fc6720 | 1273 | "Acquired semaphore[%p|%d|%d]", handle, |
4be44fcd | 1274 | units, timeout)); |
1da177e4 LT |
1275 | } |
1276 | ||
d550d98d | 1277 | return status; |
1da177e4 | 1278 | } |
1da177e4 | 1279 | |
1da177e4 LT |
1280 | /* |
1281 | * TODO: Support for units > 1? | |
1282 | */ | |
4be44fcd | 1283 | acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units) |
1da177e4 | 1284 | { |
4be44fcd | 1285 | struct semaphore *sem = (struct semaphore *)handle; |
1da177e4 | 1286 | |
7901a052 LZ |
1287 | if (!acpi_os_initialized) |
1288 | return AE_OK; | |
1289 | ||
1da177e4 | 1290 | if (!sem || (units < 1)) |
d550d98d | 1291 | return AE_BAD_PARAMETER; |
1da177e4 LT |
1292 | |
1293 | if (units > 1) | |
d550d98d | 1294 | return AE_SUPPORT; |
1da177e4 | 1295 | |
4be44fcd LB |
1296 | ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Signaling semaphore[%p|%d]\n", handle, |
1297 | units)); | |
1da177e4 LT |
1298 | |
1299 | up(sem); | |
1300 | ||
d550d98d | 1301 | return AE_OK; |
1da177e4 | 1302 | } |
4be44fcd | 1303 | |
4d946f79 | 1304 | acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read) |
1da177e4 | 1305 | { |
1da177e4 LT |
1306 | #ifdef ENABLE_DEBUGGER |
1307 | if (acpi_in_debugger) { | |
1308 | u32 chars; | |
1309 | ||
4d946f79 | 1310 | kdb_read(buffer, buffer_length); |
1da177e4 LT |
1311 | |
1312 | /* remove the CR kdb includes */ | |
1313 | chars = strlen(buffer) - 1; | |
1314 | buffer[chars] = '\0'; | |
1315 | } | |
8cfb0cdf LZ |
1316 | #else |
1317 | int ret; | |
1318 | ||
836d0830 | 1319 | ret = acpi_debugger_read_cmd(buffer, buffer_length); |
8cfb0cdf LZ |
1320 | if (ret < 0) |
1321 | return AE_ERROR; | |
1322 | if (bytes_read) | |
1323 | *bytes_read = ret; | |
1da177e4 LT |
1324 | #endif |
1325 | ||
4d946f79 | 1326 | return AE_OK; |
1da177e4 | 1327 | } |
836d0830 | 1328 | EXPORT_SYMBOL(acpi_os_get_line); |
1da177e4 | 1329 | |
8cfb0cdf LZ |
1330 | acpi_status acpi_os_wait_command_ready(void) |
1331 | { | |
1332 | int ret; | |
1333 | ||
836d0830 | 1334 | ret = acpi_debugger_wait_command_ready(); |
8cfb0cdf LZ |
1335 | if (ret < 0) |
1336 | return AE_ERROR; | |
1337 | return AE_OK; | |
1338 | } | |
1339 | ||
1340 | acpi_status acpi_os_notify_command_complete(void) | |
1341 | { | |
1342 | int ret; | |
1343 | ||
836d0830 | 1344 | ret = acpi_debugger_notify_command_complete(); |
8cfb0cdf LZ |
1345 | if (ret < 0) |
1346 | return AE_ERROR; | |
1347 | return AE_OK; | |
1348 | } | |
1349 | ||
4be44fcd | 1350 | acpi_status acpi_os_signal(u32 function, void *info) |
1da177e4 | 1351 | { |
4be44fcd | 1352 | switch (function) { |
1da177e4 LT |
1353 | case ACPI_SIGNAL_FATAL: |
1354 | printk(KERN_ERR PREFIX "Fatal opcode executed\n"); | |
1355 | break; | |
1356 | case ACPI_SIGNAL_BREAKPOINT: | |
1357 | /* | |
1358 | * AML Breakpoint | |
1359 | * ACPI spec. says to treat it as a NOP unless | |
1360 | * you are debugging. So if/when we integrate | |
1361 | * AML debugger into the kernel debugger its | |
1362 | * hook will go here. But until then it is | |
1363 | * not useful to print anything on breakpoints. | |
1364 | */ | |
1365 | break; | |
1366 | default: | |
1367 | break; | |
1368 | } | |
1369 | ||
1370 | return AE_OK; | |
1371 | } | |
4be44fcd | 1372 | |
4be44fcd | 1373 | static int __init acpi_os_name_setup(char *str) |
1da177e4 LT |
1374 | { |
1375 | char *p = acpi_os_name; | |
4be44fcd | 1376 | int count = ACPI_MAX_OVERRIDE_LEN - 1; |
1da177e4 LT |
1377 | |
1378 | if (!str || !*str) | |
1379 | return 0; | |
1380 | ||
5e2be4e0 | 1381 | for (; count-- && *str; str++) { |
1da177e4 LT |
1382 | if (isalnum(*str) || *str == ' ' || *str == ':') |
1383 | *p++ = *str; | |
1384 | else if (*str == '\'' || *str == '"') | |
1385 | continue; | |
1386 | else | |
1387 | break; | |
1388 | } | |
1389 | *p = 0; | |
1390 | ||
1391 | return 1; | |
4be44fcd | 1392 | |
1da177e4 LT |
1393 | } |
1394 | ||
1395 | __setup("acpi_os_name=", acpi_os_name_setup); | |
1396 | ||
22b5afce | 1397 | /* |
08e1d7c0 | 1398 | * Disable the auto-serialization of named objects creation methods. |
22b5afce | 1399 | * |
08e1d7c0 | 1400 | * This feature is enabled by default. It marks the AML control methods |
22b5afce BM |
1401 | * that contain the opcodes to create named objects as "Serialized". |
1402 | */ | |
08e1d7c0 | 1403 | static int __init acpi_no_auto_serialize_setup(char *str) |
1da177e4 | 1404 | { |
08e1d7c0 LZ |
1405 | acpi_gbl_auto_serialize_methods = FALSE; |
1406 | pr_info("ACPI: auto-serialization disabled\n"); | |
1da177e4 LT |
1407 | |
1408 | return 1; | |
1409 | } | |
1410 | ||
08e1d7c0 | 1411 | __setup("acpi_no_auto_serialize", acpi_no_auto_serialize_setup); |
1da177e4 | 1412 | |
df92e695 TR |
1413 | /* Check of resource interference between native drivers and ACPI |
1414 | * OperationRegions (SystemIO and System Memory only). | |
1415 | * IO ports and memory declared in ACPI might be used by the ACPI subsystem | |
1416 | * in arbitrary AML code and can interfere with legacy drivers. | |
1417 | * acpi_enforce_resources= can be set to: | |
1418 | * | |
7e90560c | 1419 | * - strict (default) (2) |
df92e695 | 1420 | * -> further driver trying to access the resources will not load |
7e90560c | 1421 | * - lax (1) |
df92e695 TR |
1422 | * -> further driver trying to access the resources will load, but you |
1423 | * get a system message that something might go wrong... | |
1424 | * | |
1425 | * - no (0) | |
1426 | * -> ACPI Operation Region resources will not be registered | |
1427 | * | |
1428 | */ | |
1429 | #define ENFORCE_RESOURCES_STRICT 2 | |
1430 | #define ENFORCE_RESOURCES_LAX 1 | |
1431 | #define ENFORCE_RESOURCES_NO 0 | |
1432 | ||
7e90560c | 1433 | static unsigned int acpi_enforce_resources = ENFORCE_RESOURCES_STRICT; |
df92e695 TR |
1434 | |
1435 | static int __init acpi_enforce_resources_setup(char *str) | |
1436 | { | |
1437 | if (str == NULL || *str == '\0') | |
1438 | return 0; | |
1439 | ||
1440 | if (!strcmp("strict", str)) | |
1441 | acpi_enforce_resources = ENFORCE_RESOURCES_STRICT; | |
1442 | else if (!strcmp("lax", str)) | |
1443 | acpi_enforce_resources = ENFORCE_RESOURCES_LAX; | |
1444 | else if (!strcmp("no", str)) | |
1445 | acpi_enforce_resources = ENFORCE_RESOURCES_NO; | |
1446 | ||
1447 | return 1; | |
1448 | } | |
1449 | ||
1450 | __setup("acpi_enforce_resources=", acpi_enforce_resources_setup); | |
1451 | ||
1452 | /* Check for resource conflicts between ACPI OperationRegions and native | |
1453 | * drivers */ | |
876fba43 | 1454 | int acpi_check_resource_conflict(const struct resource *res) |
df92e695 | 1455 | { |
f654c0fe LM |
1456 | acpi_adr_space_type space_id; |
1457 | acpi_size length; | |
1458 | u8 warn = 0; | |
1459 | int clash = 0; | |
df92e695 TR |
1460 | |
1461 | if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) | |
1462 | return 0; | |
1463 | if (!(res->flags & IORESOURCE_IO) && !(res->flags & IORESOURCE_MEM)) | |
1464 | return 0; | |
1465 | ||
f654c0fe LM |
1466 | if (res->flags & IORESOURCE_IO) |
1467 | space_id = ACPI_ADR_SPACE_SYSTEM_IO; | |
1468 | else | |
1469 | space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY; | |
df92e695 | 1470 | |
e4f52244 | 1471 | length = resource_size(res); |
f654c0fe LM |
1472 | if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) |
1473 | warn = 1; | |
1474 | clash = acpi_check_address_range(space_id, res->start, length, warn); | |
df92e695 TR |
1475 | |
1476 | if (clash) { | |
1477 | if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) { | |
14f03343 JD |
1478 | if (acpi_enforce_resources == ENFORCE_RESOURCES_LAX) |
1479 | printk(KERN_NOTICE "ACPI: This conflict may" | |
1480 | " cause random problems and system" | |
1481 | " instability\n"); | |
1482 | printk(KERN_INFO "ACPI: If an ACPI driver is available" | |
1483 | " for this device, you should use it instead of" | |
1484 | " the native driver\n"); | |
df92e695 TR |
1485 | } |
1486 | if (acpi_enforce_resources == ENFORCE_RESOURCES_STRICT) | |
1487 | return -EBUSY; | |
1488 | } | |
1489 | return 0; | |
1490 | } | |
443dea72 | 1491 | EXPORT_SYMBOL(acpi_check_resource_conflict); |
df92e695 TR |
1492 | |
1493 | int acpi_check_region(resource_size_t start, resource_size_t n, | |
1494 | const char *name) | |
1495 | { | |
1496 | struct resource res = { | |
1497 | .start = start, | |
1498 | .end = start + n - 1, | |
1499 | .name = name, | |
1500 | .flags = IORESOURCE_IO, | |
1501 | }; | |
1502 | ||
1503 | return acpi_check_resource_conflict(&res); | |
1504 | } | |
1505 | EXPORT_SYMBOL(acpi_check_region); | |
1506 | ||
d2d2e3c4 HK |
1507 | static acpi_status acpi_deactivate_mem_region(acpi_handle handle, u32 level, |
1508 | void *_res, void **return_value) | |
1509 | { | |
1510 | struct acpi_mem_space_context **mem_ctx; | |
1511 | union acpi_operand_object *handler_obj; | |
1512 | union acpi_operand_object *region_obj2; | |
1513 | union acpi_operand_object *region_obj; | |
1514 | struct resource *res = _res; | |
1515 | acpi_status status; | |
1516 | ||
1517 | region_obj = acpi_ns_get_attached_object(handle); | |
1518 | if (!region_obj) | |
1519 | return AE_OK; | |
1520 | ||
1521 | handler_obj = region_obj->region.handler; | |
1522 | if (!handler_obj) | |
1523 | return AE_OK; | |
1524 | ||
1525 | if (region_obj->region.space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) | |
1526 | return AE_OK; | |
1527 | ||
1528 | if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) | |
1529 | return AE_OK; | |
1530 | ||
1531 | region_obj2 = acpi_ns_get_secondary_object(region_obj); | |
1532 | if (!region_obj2) | |
1533 | return AE_OK; | |
1534 | ||
1535 | mem_ctx = (void *)®ion_obj2->extra.region_context; | |
1536 | ||
1537 | if (!(mem_ctx[0]->address >= res->start && | |
1538 | mem_ctx[0]->address < res->end)) | |
1539 | return AE_OK; | |
1540 | ||
1541 | status = handler_obj->address_space.setup(region_obj, | |
1542 | ACPI_REGION_DEACTIVATE, | |
1543 | NULL, (void **)mem_ctx); | |
1544 | if (ACPI_SUCCESS(status)) | |
1545 | region_obj->region.flags &= ~(AOPOBJ_SETUP_COMPLETE); | |
1546 | ||
1547 | return status; | |
1548 | } | |
1549 | ||
1550 | /** | |
1551 | * acpi_release_memory - Release any mappings done to a memory region | |
1552 | * @handle: Handle to namespace node | |
1553 | * @res: Memory resource | |
1554 | * @level: A level that terminates the search | |
1555 | * | |
1556 | * Walks through @handle and unmaps all SystemMemory Operation Regions that | |
1557 | * overlap with @res and that have already been activated (mapped). | |
1558 | * | |
1559 | * This is a helper that allows drivers to place special requirements on memory | |
1560 | * region that may overlap with operation regions, primarily allowing them to | |
1561 | * safely map the region as non-cached memory. | |
1562 | * | |
1563 | * The unmapped Operation Regions will be automatically remapped next time they | |
1564 | * are called, so the drivers do not need to do anything else. | |
1565 | */ | |
1566 | acpi_status acpi_release_memory(acpi_handle handle, struct resource *res, | |
1567 | u32 level) | |
1568 | { | |
1569 | if (!(res->flags & IORESOURCE_MEM)) | |
1570 | return AE_TYPE; | |
1571 | ||
1572 | return acpi_walk_namespace(ACPI_TYPE_REGION, handle, level, | |
1573 | acpi_deactivate_mem_region, NULL, res, NULL); | |
1574 | } | |
1575 | EXPORT_SYMBOL_GPL(acpi_release_memory); | |
1576 | ||
70dd6bea JD |
1577 | /* |
1578 | * Let drivers know whether the resource checks are effective | |
1579 | */ | |
1580 | int acpi_resources_are_enforced(void) | |
1581 | { | |
1582 | return acpi_enforce_resources == ENFORCE_RESOURCES_STRICT; | |
1583 | } | |
1584 | EXPORT_SYMBOL(acpi_resources_are_enforced); | |
1585 | ||
9f63b88b LM |
1586 | /* |
1587 | * Deallocate the memory for a spinlock. | |
1588 | */ | |
1589 | void acpi_os_delete_lock(acpi_spinlock handle) | |
1590 | { | |
1591 | ACPI_FREE(handle); | |
1592 | } | |
1593 | ||
73459f73 RM |
1594 | /* |
1595 | * Acquire a spinlock. | |
1596 | * | |
1597 | * handle is a pointer to the spinlock_t. | |
73459f73 RM |
1598 | */ |
1599 | ||
967440e3 | 1600 | acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp) |
2288eba5 | 1601 | __acquires(lockp) |
73459f73 | 1602 | { |
b8e4d893 | 1603 | acpi_cpu_flags flags; |
967440e3 | 1604 | spin_lock_irqsave(lockp, flags); |
73459f73 RM |
1605 | return flags; |
1606 | } | |
1607 | ||
1608 | /* | |
1609 | * Release a spinlock. See above. | |
1610 | */ | |
1611 | ||
967440e3 | 1612 | void acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags flags) |
2288eba5 | 1613 | __releases(lockp) |
73459f73 | 1614 | { |
967440e3 | 1615 | spin_unlock_irqrestore(lockp, flags); |
73459f73 RM |
1616 | } |
1617 | ||
73459f73 RM |
1618 | #ifndef ACPI_USE_LOCAL_CACHE |
1619 | ||
1620 | /******************************************************************************* | |
1621 | * | |
1622 | * FUNCTION: acpi_os_create_cache | |
1623 | * | |
b229cf92 BM |
1624 | * PARAMETERS: name - Ascii name for the cache |
1625 | * size - Size of each cached object | |
1626 | * depth - Maximum depth of the cache (in objects) <ignored> | |
1627 | * cache - Where the new cache object is returned | |
73459f73 | 1628 | * |
b229cf92 | 1629 | * RETURN: status |
73459f73 RM |
1630 | * |
1631 | * DESCRIPTION: Create a cache object | |
1632 | * | |
1633 | ******************************************************************************/ | |
1634 | ||
1635 | acpi_status | |
4be44fcd | 1636 | acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache) |
73459f73 | 1637 | { |
20c2df83 | 1638 | *cache = kmem_cache_create(name, size, 0, 0, NULL); |
a6fdbf90 | 1639 | if (*cache == NULL) |
b229cf92 BM |
1640 | return AE_ERROR; |
1641 | else | |
1642 | return AE_OK; | |
73459f73 RM |
1643 | } |
1644 | ||
1645 | /******************************************************************************* | |
1646 | * | |
1647 | * FUNCTION: acpi_os_purge_cache | |
1648 | * | |
1649 | * PARAMETERS: Cache - Handle to cache object | |
1650 | * | |
1651 | * RETURN: Status | |
1652 | * | |
1653 | * DESCRIPTION: Free all objects within the requested cache. | |
1654 | * | |
1655 | ******************************************************************************/ | |
1656 | ||
4be44fcd | 1657 | acpi_status acpi_os_purge_cache(acpi_cache_t * cache) |
73459f73 | 1658 | { |
50dd0969 | 1659 | kmem_cache_shrink(cache); |
4be44fcd | 1660 | return (AE_OK); |
73459f73 RM |
1661 | } |
1662 | ||
1663 | /******************************************************************************* | |
1664 | * | |
1665 | * FUNCTION: acpi_os_delete_cache | |
1666 | * | |
1667 | * PARAMETERS: Cache - Handle to cache object | |
1668 | * | |
1669 | * RETURN: Status | |
1670 | * | |
1671 | * DESCRIPTION: Free all objects within the requested cache and delete the | |
1672 | * cache object. | |
1673 | * | |
1674 | ******************************************************************************/ | |
1675 | ||
4be44fcd | 1676 | acpi_status acpi_os_delete_cache(acpi_cache_t * cache) |
73459f73 | 1677 | { |
1a1d92c1 | 1678 | kmem_cache_destroy(cache); |
4be44fcd | 1679 | return (AE_OK); |
73459f73 RM |
1680 | } |
1681 | ||
1682 | /******************************************************************************* | |
1683 | * | |
1684 | * FUNCTION: acpi_os_release_object | |
1685 | * | |
1686 | * PARAMETERS: Cache - Handle to cache object | |
1687 | * Object - The object to be released | |
1688 | * | |
1689 | * RETURN: None | |
1690 | * | |
1691 | * DESCRIPTION: Release an object to the specified cache. If cache is full, | |
1692 | * the object is deleted. | |
1693 | * | |
1694 | ******************************************************************************/ | |
1695 | ||
4be44fcd | 1696 | acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object) |
73459f73 | 1697 | { |
4be44fcd LB |
1698 | kmem_cache_free(cache, object); |
1699 | return (AE_OK); | |
73459f73 | 1700 | } |
73459f73 | 1701 | #endif |
d362edaf | 1702 | |
a94e88cd | 1703 | static int __init acpi_no_static_ssdt_setup(char *s) |
b75dd297 | 1704 | { |
a94e88cd LZ |
1705 | acpi_gbl_disable_ssdt_table_install = TRUE; |
1706 | pr_info("ACPI: static SSDT installation disabled\n"); | |
b75dd297 | 1707 | |
a94e88cd | 1708 | return 0; |
b75dd297 LZ |
1709 | } |
1710 | ||
a94e88cd | 1711 | early_param("acpi_no_static_ssdt", acpi_no_static_ssdt_setup); |
b75dd297 | 1712 | |
4dde507f LZ |
1713 | static int __init acpi_disable_return_repair(char *s) |
1714 | { | |
1715 | printk(KERN_NOTICE PREFIX | |
1716 | "ACPI: Predefined validation mechanism disabled\n"); | |
1717 | acpi_gbl_disable_auto_repair = TRUE; | |
1718 | ||
1719 | return 1; | |
1720 | } | |
1721 | ||
1722 | __setup("acpica_no_return_repair", acpi_disable_return_repair); | |
1723 | ||
d362edaf MS |
1724 | acpi_status __init acpi_os_initialize(void) |
1725 | { | |
1726 | acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1a_event_block); | |
1727 | acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1b_event_block); | |
1728 | acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe0_block); | |
1729 | acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe1_block); | |
a4714a89 RW |
1730 | if (acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) { |
1731 | /* | |
1732 | * Use acpi_os_map_generic_address to pre-map the reset | |
1733 | * register if it's in system memory. | |
1734 | */ | |
1735 | int rv; | |
1736 | ||
1737 | rv = acpi_os_map_generic_address(&acpi_gbl_FADT.reset_register); | |
1738 | pr_debug(PREFIX "%s: map reset_reg status %d\n", __func__, rv); | |
1739 | } | |
7901a052 | 1740 | acpi_os_initialized = true; |
d362edaf MS |
1741 | |
1742 | return AE_OK; | |
1743 | } | |
1744 | ||
32d47eef | 1745 | acpi_status __init acpi_os_initialize1(void) |
d362edaf | 1746 | { |
44d2588e TH |
1747 | kacpid_wq = alloc_workqueue("kacpid", 0, 1); |
1748 | kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1); | |
d783156e | 1749 | kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0); |
d362edaf MS |
1750 | BUG_ON(!kacpid_wq); |
1751 | BUG_ON(!kacpi_notify_wq); | |
1752 | BUG_ON(!kacpi_hotplug_wq); | |
e5f660eb | 1753 | acpi_osi_init(); |
d362edaf MS |
1754 | return AE_OK; |
1755 | } | |
1756 | ||
1757 | acpi_status acpi_os_terminate(void) | |
1758 | { | |
1759 | if (acpi_irq_handler) { | |
23fe3630 | 1760 | acpi_os_remove_interrupt_handler(acpi_gbl_FADT.sci_interrupt, |
d362edaf MS |
1761 | acpi_irq_handler); |
1762 | } | |
1763 | ||
1764 | acpi_os_unmap_generic_address(&acpi_gbl_FADT.xgpe1_block); | |
1765 | acpi_os_unmap_generic_address(&acpi_gbl_FADT.xgpe0_block); | |
1766 | acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1b_event_block); | |
1767 | acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1a_event_block); | |
a4714a89 RW |
1768 | if (acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) |
1769 | acpi_os_unmap_generic_address(&acpi_gbl_FADT.reset_register); | |
d362edaf MS |
1770 | |
1771 | destroy_workqueue(kacpid_wq); | |
1772 | destroy_workqueue(kacpi_notify_wq); | |
1773 | destroy_workqueue(kacpi_hotplug_wq); | |
1774 | ||
1775 | return AE_OK; | |
1776 | } | |
09f98a82 TL |
1777 | |
1778 | acpi_status acpi_os_prepare_sleep(u8 sleep_state, u32 pm1a_control, | |
1779 | u32 pm1b_control) | |
1780 | { | |
1781 | int rc = 0; | |
1782 | if (__acpi_os_prepare_sleep) | |
1783 | rc = __acpi_os_prepare_sleep(sleep_state, | |
1784 | pm1a_control, pm1b_control); | |
1785 | if (rc < 0) | |
1786 | return AE_ERROR; | |
1787 | else if (rc > 0) | |
0fc5e8f4 | 1788 | return AE_CTRL_TERMINATE; |
09f98a82 TL |
1789 | |
1790 | return AE_OK; | |
1791 | } | |
1792 | ||
1793 | void acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state, | |
1794 | u32 pm1a_ctrl, u32 pm1b_ctrl)) | |
1795 | { | |
1796 | __acpi_os_prepare_sleep = func; | |
1797 | } | |
92d8aff3 | 1798 | |
0fc5e8f4 | 1799 | #if (ACPI_REDUCED_HARDWARE) |
d6b47b12 BG |
1800 | acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a, |
1801 | u32 val_b) | |
1802 | { | |
1803 | int rc = 0; | |
1804 | if (__acpi_os_prepare_extended_sleep) | |
1805 | rc = __acpi_os_prepare_extended_sleep(sleep_state, | |
1806 | val_a, val_b); | |
1807 | if (rc < 0) | |
1808 | return AE_ERROR; | |
1809 | else if (rc > 0) | |
0fc5e8f4 | 1810 | return AE_CTRL_TERMINATE; |
d6b47b12 BG |
1811 | |
1812 | return AE_OK; | |
1813 | } | |
0fc5e8f4 LZ |
1814 | #else |
1815 | acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a, | |
1816 | u32 val_b) | |
1817 | { | |
1818 | return AE_OK; | |
1819 | } | |
1820 | #endif | |
d6b47b12 BG |
1821 | |
1822 | void acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state, | |
1823 | u32 val_a, u32 val_b)) | |
1824 | { | |
1825 | __acpi_os_prepare_extended_sleep = func; | |
1826 | } | |
0fc5e8f4 LZ |
1827 | |
1828 | acpi_status acpi_os_enter_sleep(u8 sleep_state, | |
1829 | u32 reg_a_value, u32 reg_b_value) | |
1830 | { | |
1831 | acpi_status status; | |
1832 | ||
1833 | if (acpi_gbl_reduced_hardware) | |
1834 | status = acpi_os_prepare_extended_sleep(sleep_state, | |
1835 | reg_a_value, | |
1836 | reg_b_value); | |
1837 | else | |
1838 | status = acpi_os_prepare_sleep(sleep_state, | |
1839 | reg_a_value, reg_b_value); | |
1840 | return status; | |
1841 | } |