xref: /openbmc/linux/drivers/acpi/osl.c (revision 214c2362)
1c942fddfSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds  *  acpi_osl.c - OS-dependent functions ($Revision: 83 $)
41da177e4SLinus Torvalds  *
51da177e4SLinus Torvalds  *  Copyright (C) 2000       Andrew Henroid
61da177e4SLinus Torvalds  *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
71da177e4SLinus Torvalds  *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
8f1241c87SMatthew Wilcox  *  Copyright (c) 2008 Intel Corporation
9f1241c87SMatthew Wilcox  *   Author: Matthew Wilcox <willy@linux.intel.com>
101da177e4SLinus Torvalds  */
111da177e4SLinus Torvalds 
128aef273eSRafael J. Wysocki #define pr_fmt(fmt) "ACPI: OSL: " fmt
138aef273eSRafael J. Wysocki 
141da177e4SLinus Torvalds #include <linux/module.h>
151da177e4SLinus Torvalds #include <linux/kernel.h>
161da177e4SLinus Torvalds #include <linux/slab.h>
171da177e4SLinus Torvalds #include <linux/mm.h>
18ba242d5bSMyron Stowe #include <linux/highmem.h>
19bee6f871SJoel Fernandes (Google) #include <linux/lockdep.h>
201da177e4SLinus Torvalds #include <linux/pci.h>
211da177e4SLinus Torvalds #include <linux/interrupt.h>
221da177e4SLinus Torvalds #include <linux/kmod.h>
231da177e4SLinus Torvalds #include <linux/delay.h>
241da177e4SLinus Torvalds #include <linux/workqueue.h>
251da177e4SLinus Torvalds #include <linux/nmi.h>
26ad71860aSAlexey Starikovskiy #include <linux/acpi.h>
271da177e4SLinus Torvalds #include <linux/efi.h>
28df92e695SThomas Renninger #include <linux/ioport.h>
29df92e695SThomas Renninger #include <linux/list.h>
30f1241c87SMatthew Wilcox #include <linux/jiffies.h>
31f1241c87SMatthew Wilcox #include <linux/semaphore.h>
3241fa1ee9SJosh Boyer #include <linux/security.h>
33f1241c87SMatthew Wilcox 
34f1241c87SMatthew Wilcox #include <asm/io.h>
357c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
362f8e2c87SChristoph Hellwig #include <linux/io-64-nonatomic-lo-hi.h>
37f1241c87SMatthew Wilcox 
38d2d2e3c4SHeikki Krogerus #include "acpica/accommon.h"
391129c92fSLv Zheng #include "internal.h"
401da177e4SLinus Torvalds 
418aef273eSRafael J. Wysocki /* Definitions for ACPI_DEBUG_PRINT() */
421da177e4SLinus Torvalds #define _COMPONENT		ACPI_OS_SERVICES
43f52fd66dSLen Brown ACPI_MODULE_NAME("osl");
4407070e12SHanjun Guo 
454be44fcdSLen Brown struct acpi_os_dpc {
461da177e4SLinus Torvalds 	acpi_osd_exec_callback function;
471da177e4SLinus Torvalds 	void *context;
4865f27f38SDavid Howells 	struct work_struct work;
491da177e4SLinus Torvalds };
501da177e4SLinus Torvalds 
511da177e4SLinus Torvalds #ifdef ENABLE_DEBUGGER
521da177e4SLinus Torvalds #include <linux/kdb.h>
531da177e4SLinus Torvalds 
541da177e4SLinus Torvalds /* stuff for debugger support */
551da177e4SLinus Torvalds int acpi_in_debugger;
561da177e4SLinus Torvalds EXPORT_SYMBOL(acpi_in_debugger);
571da177e4SLinus Torvalds #endif				/*ENABLE_DEBUGGER */
581da177e4SLinus Torvalds 
5909f98a82STang Liang static int (*__acpi_os_prepare_sleep)(u8 sleep_state, u32 pm1a_ctrl,
6009f98a82STang Liang 				      u32 pm1b_ctrl);
61d6b47b12SBen Guthro static int (*__acpi_os_prepare_extended_sleep)(u8 sleep_state, u32 val_a,
62d6b47b12SBen Guthro 				      u32 val_b);
6309f98a82STang Liang 
641da177e4SLinus Torvalds static acpi_osd_handler acpi_irq_handler;
651da177e4SLinus Torvalds static void *acpi_irq_context;
661da177e4SLinus Torvalds static struct workqueue_struct *kacpid_wq;
6788db5e14SAlexey Starikovskiy static struct workqueue_struct *kacpi_notify_wq;
6892d8aff3SYinghai Lu static struct workqueue_struct *kacpi_hotplug_wq;
697901a052SLv Zheng static bool acpi_os_initialized;
7049e4b843SChen Yu unsigned int acpi_sci_irq = INVALID_ACPI_IRQ;
718d3523fbSLv Zheng bool acpi_permanent_mmap = false;
721da177e4SLinus Torvalds 
73620242aeSMyron Stowe /*
74620242aeSMyron Stowe  * This list of permanent mappings is for memory that may be accessed from
75620242aeSMyron Stowe  * interrupt context, where we can't do the ioremap().
76620242aeSMyron Stowe  */
77620242aeSMyron Stowe struct acpi_ioremap {
78620242aeSMyron Stowe 	struct list_head list;
79620242aeSMyron Stowe 	void __iomem *virt;
80620242aeSMyron Stowe 	acpi_physical_address phys;
81620242aeSMyron Stowe 	acpi_size size;
821757659dSRafael J. Wysocki 	union {
83b7c1faddSRafael J. Wysocki 		unsigned long refcount;
841757659dSRafael J. Wysocki 		struct rcu_work rwork;
851757659dSRafael J. Wysocki 	} track;
86620242aeSMyron Stowe };
87620242aeSMyron Stowe 
88620242aeSMyron Stowe static LIST_HEAD(acpi_ioremaps);
897bbb8903SRafael J. Wysocki static DEFINE_MUTEX(acpi_ioremap_lock);
90bee6f871SJoel Fernandes (Google) #define acpi_ioremap_lock_held() lock_is_held(&acpi_ioremap_lock.dep_map)
91620242aeSMyron Stowe 
acpi_request_region(struct acpi_generic_address * gas,unsigned int length,char * desc)92bc9ffce2SMyron Stowe static void __init acpi_request_region (struct acpi_generic_address *gas,
939a47cdb1SBjorn Helgaas 	unsigned int length, char *desc)
949a47cdb1SBjorn Helgaas {
95bc9ffce2SMyron Stowe 	u64 addr;
96bc9ffce2SMyron Stowe 
97bc9ffce2SMyron Stowe 	/* Handle possible alignment issues */
98bc9ffce2SMyron Stowe 	memcpy(&addr, &gas->address, sizeof(addr));
99bc9ffce2SMyron Stowe 	if (!addr || !length)
1009a47cdb1SBjorn Helgaas 		return;
1019a47cdb1SBjorn Helgaas 
1020294112eSRafael J. Wysocki 	/* Resources are never freed */
1030294112eSRafael J. Wysocki 	if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO)
1040294112eSRafael J. Wysocki 		request_region(addr, length, desc);
1050294112eSRafael J. Wysocki 	else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
1060294112eSRafael J. Wysocki 		request_mem_region(addr, length, desc);
1079a47cdb1SBjorn Helgaas }
1089a47cdb1SBjorn Helgaas 
acpi_reserve_resources(void)1090294112eSRafael J. Wysocki static int __init acpi_reserve_resources(void)
1109a47cdb1SBjorn Helgaas {
111eee3c859SLen Brown 	acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length,
1129a47cdb1SBjorn Helgaas 		"ACPI PM1a_EVT_BLK");
1139a47cdb1SBjorn Helgaas 
114eee3c859SLen Brown 	acpi_request_region(&acpi_gbl_FADT.xpm1b_event_block, acpi_gbl_FADT.pm1_event_length,
1159a47cdb1SBjorn Helgaas 		"ACPI PM1b_EVT_BLK");
1169a47cdb1SBjorn Helgaas 
117eee3c859SLen Brown 	acpi_request_region(&acpi_gbl_FADT.xpm1a_control_block, acpi_gbl_FADT.pm1_control_length,
1189a47cdb1SBjorn Helgaas 		"ACPI PM1a_CNT_BLK");
1199a47cdb1SBjorn Helgaas 
120eee3c859SLen Brown 	acpi_request_region(&acpi_gbl_FADT.xpm1b_control_block, acpi_gbl_FADT.pm1_control_length,
1219a47cdb1SBjorn Helgaas 		"ACPI PM1b_CNT_BLK");
1229a47cdb1SBjorn Helgaas 
123eee3c859SLen Brown 	if (acpi_gbl_FADT.pm_timer_length == 4)
124eee3c859SLen Brown 		acpi_request_region(&acpi_gbl_FADT.xpm_timer_block, 4, "ACPI PM_TMR");
1259a47cdb1SBjorn Helgaas 
126eee3c859SLen Brown 	acpi_request_region(&acpi_gbl_FADT.xpm2_control_block, acpi_gbl_FADT.pm2_control_length,
1279a47cdb1SBjorn Helgaas 		"ACPI PM2_CNT_BLK");
1289a47cdb1SBjorn Helgaas 
1299a47cdb1SBjorn Helgaas 	/* Length of GPE blocks must be a non-negative multiple of 2 */
1309a47cdb1SBjorn Helgaas 
131eee3c859SLen Brown 	if (!(acpi_gbl_FADT.gpe0_block_length & 0x1))
132eee3c859SLen Brown 		acpi_request_region(&acpi_gbl_FADT.xgpe0_block,
133eee3c859SLen Brown 			       acpi_gbl_FADT.gpe0_block_length, "ACPI GPE0_BLK");
1349a47cdb1SBjorn Helgaas 
135eee3c859SLen Brown 	if (!(acpi_gbl_FADT.gpe1_block_length & 0x1))
136eee3c859SLen Brown 		acpi_request_region(&acpi_gbl_FADT.xgpe1_block,
137eee3c859SLen Brown 			       acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK");
1380294112eSRafael J. Wysocki 
1390294112eSRafael J. Wysocki 	return 0;
1409a47cdb1SBjorn Helgaas }
1410294112eSRafael J. Wysocki fs_initcall_sync(acpi_reserve_resources);
1429a47cdb1SBjorn Helgaas 
acpi_os_printf(const char * fmt,...)1434be44fcdSLen Brown void acpi_os_printf(const char *fmt, ...)
1441da177e4SLinus Torvalds {
1451da177e4SLinus Torvalds 	va_list args;
1461da177e4SLinus Torvalds 	va_start(args, fmt);
1471da177e4SLinus Torvalds 	acpi_os_vprintf(fmt, args);
1481da177e4SLinus Torvalds 	va_end(args);
1491da177e4SLinus Torvalds }
150836d0830SLv Zheng EXPORT_SYMBOL(acpi_os_printf);
1514be44fcdSLen Brown 
acpi_os_vprintf(const char * fmt,va_list args)1524be44fcdSLen Brown void acpi_os_vprintf(const char *fmt, va_list args)
1531da177e4SLinus Torvalds {
1541da177e4SLinus Torvalds 	static char buffer[512];
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds 	vsprintf(buffer, fmt, args);
1571da177e4SLinus Torvalds 
1581da177e4SLinus Torvalds #ifdef ENABLE_DEBUGGER
1591da177e4SLinus Torvalds 	if (acpi_in_debugger) {
1601da177e4SLinus Torvalds 		kdb_printf("%s", buffer);
1611da177e4SLinus Torvalds 	} else {
162abc4b9a5SJoe Perches 		if (printk_get_level(buffer))
163abc4b9a5SJoe Perches 			printk("%s", buffer);
164abc4b9a5SJoe Perches 		else
1654d939155SFrank Seidel 			printk(KERN_CONT "%s", buffer);
1661da177e4SLinus Torvalds 	}
1671da177e4SLinus Torvalds #else
168abc4b9a5SJoe Perches 	if (acpi_debugger_write_log(buffer) < 0) {
169abc4b9a5SJoe Perches 		if (printk_get_level(buffer))
170abc4b9a5SJoe Perches 			printk("%s", buffer);
171abc4b9a5SJoe Perches 		else
1724d939155SFrank Seidel 			printk(KERN_CONT "%s", buffer);
173abc4b9a5SJoe Perches 	}
1741da177e4SLinus Torvalds #endif
1751da177e4SLinus Torvalds }
1761da177e4SLinus Torvalds 
1774996c023STakao Indoh #ifdef CONFIG_KEXEC
1784996c023STakao Indoh static unsigned long acpi_rsdp;
setup_acpi_rsdp(char * arg)1794996c023STakao Indoh static int __init setup_acpi_rsdp(char *arg)
1804996c023STakao Indoh {
1815dcb9ca8SAndy Shevchenko 	return kstrtoul(arg, 16, &acpi_rsdp);
1824996c023STakao Indoh }
1834996c023STakao Indoh early_param("acpi_rsdp", setup_acpi_rsdp);
1844996c023STakao Indoh #endif
1854996c023STakao Indoh 
acpi_os_get_root_pointer(void)186ad71860aSAlexey Starikovskiy acpi_physical_address __init acpi_os_get_root_pointer(void)
1871da177e4SLinus Torvalds {
188dfc9327aSJuergen Gross 	acpi_physical_address pa;
1892fb65f09SAndy Shevchenko 
1904996c023STakao Indoh #ifdef CONFIG_KEXEC
19141fa1ee9SJosh Boyer 	/*
19241fa1ee9SJosh Boyer 	 * We may have been provided with an RSDP on the command line,
19341fa1ee9SJosh Boyer 	 * but if a malicious user has done so they may be pointing us
19441fa1ee9SJosh Boyer 	 * at modified ACPI tables that could alter kernel behaviour -
19541fa1ee9SJosh Boyer 	 * so, we check the lockdown status before making use of
19641fa1ee9SJosh Boyer 	 * it. If we trust it then also stash it in an architecture
19741fa1ee9SJosh Boyer 	 * specific location (if appropriate) so it can be carried
19841fa1ee9SJosh Boyer 	 * over further kexec()s.
19941fa1ee9SJosh Boyer 	 */
20041fa1ee9SJosh Boyer 	if (acpi_rsdp && !security_locked_down(LOCKDOWN_ACPI_TABLES)) {
20141fa1ee9SJosh Boyer 		acpi_arch_set_root_pointer(acpi_rsdp);
2024996c023STakao Indoh 		return acpi_rsdp;
20341fa1ee9SJosh Boyer 	}
2044996c023STakao Indoh #endif
205dfc9327aSJuergen Gross 	pa = acpi_arch_get_root_pointer();
206dfc9327aSJuergen Gross 	if (pa)
207dfc9327aSJuergen Gross 		return pa;
2084996c023STakao Indoh 
20983e68189SMatt Fleming 	if (efi_enabled(EFI_CONFIG_TABLES)) {
210b2c99e3cSBjorn Helgaas 		if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
211ad71860aSAlexey Starikovskiy 			return efi.acpi20;
2122fb65f09SAndy Shevchenko 		if (efi.acpi != EFI_INVALID_TABLE_ADDR)
213ad71860aSAlexey Starikovskiy 			return efi.acpi;
2142e670dedSHanjun Guo 		pr_err("System description tables not found\n");
2158a1664beSGraeme Gregory 	} else if (IS_ENABLED(CONFIG_ACPI_LEGACY_TABLES_LOOKUP)) {
216239665a3SLen Brown 		acpi_find_root_pointer(&pa);
217239665a3SLen Brown 	}
2188a1664beSGraeme Gregory 
2192fb65f09SAndy Shevchenko 	return pa;
2201da177e4SLinus Torvalds }
2211da177e4SLinus Torvalds 
22278cdb3edSMyron Stowe /* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */
2234a3cba5eSMyron Stowe static struct acpi_ioremap *
acpi_map_lookup(acpi_physical_address phys,acpi_size size)2244a3cba5eSMyron Stowe acpi_map_lookup(acpi_physical_address phys, acpi_size size)
225620242aeSMyron Stowe {
226620242aeSMyron Stowe 	struct acpi_ioremap *map;
227620242aeSMyron Stowe 
228bee6f871SJoel Fernandes (Google) 	list_for_each_entry_rcu(map, &acpi_ioremaps, list, acpi_ioremap_lock_held())
229620242aeSMyron Stowe 		if (map->phys <= phys &&
230620242aeSMyron Stowe 		    phys + size <= map->phys + map->size)
2314a3cba5eSMyron Stowe 			return map;
2324a3cba5eSMyron Stowe 
2334a3cba5eSMyron Stowe 	return NULL;
2344a3cba5eSMyron Stowe }
2354a3cba5eSMyron Stowe 
2364a3cba5eSMyron Stowe /* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */
2374a3cba5eSMyron Stowe static void __iomem *
acpi_map_vaddr_lookup(acpi_physical_address phys,unsigned int size)2384a3cba5eSMyron Stowe acpi_map_vaddr_lookup(acpi_physical_address phys, unsigned int size)
2394a3cba5eSMyron Stowe {
2404a3cba5eSMyron Stowe 	struct acpi_ioremap *map;
2414a3cba5eSMyron Stowe 
2424a3cba5eSMyron Stowe 	map = acpi_map_lookup(phys, size);
2434a3cba5eSMyron Stowe 	if (map)
244620242aeSMyron Stowe 		return map->virt + (phys - map->phys);
245620242aeSMyron Stowe 
246620242aeSMyron Stowe 	return NULL;
247620242aeSMyron Stowe }
248620242aeSMyron Stowe 
acpi_os_get_iomem(acpi_physical_address phys,unsigned int size)24913606a2dSRafael J. Wysocki void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size)
25013606a2dSRafael J. Wysocki {
25113606a2dSRafael J. Wysocki 	struct acpi_ioremap *map;
25213606a2dSRafael J. Wysocki 	void __iomem *virt = NULL;
25313606a2dSRafael J. Wysocki 
25413606a2dSRafael J. Wysocki 	mutex_lock(&acpi_ioremap_lock);
25513606a2dSRafael J. Wysocki 	map = acpi_map_lookup(phys, size);
25613606a2dSRafael J. Wysocki 	if (map) {
25713606a2dSRafael J. Wysocki 		virt = map->virt + (phys - map->phys);
2581757659dSRafael J. Wysocki 		map->track.refcount++;
25913606a2dSRafael J. Wysocki 	}
26013606a2dSRafael J. Wysocki 	mutex_unlock(&acpi_ioremap_lock);
26113606a2dSRafael J. Wysocki 	return virt;
26213606a2dSRafael J. Wysocki }
26313606a2dSRafael J. Wysocki EXPORT_SYMBOL_GPL(acpi_os_get_iomem);
26413606a2dSRafael J. Wysocki 
26578cdb3edSMyron Stowe /* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */
266620242aeSMyron Stowe static struct acpi_ioremap *
acpi_map_lookup_virt(void __iomem * virt,acpi_size size)267620242aeSMyron Stowe acpi_map_lookup_virt(void __iomem *virt, acpi_size size)
268620242aeSMyron Stowe {
269620242aeSMyron Stowe 	struct acpi_ioremap *map;
270620242aeSMyron Stowe 
271bee6f871SJoel Fernandes (Google) 	list_for_each_entry_rcu(map, &acpi_ioremaps, list, acpi_ioremap_lock_held())
2724a3cba5eSMyron Stowe 		if (map->virt <= virt &&
2734a3cba5eSMyron Stowe 		    virt + size <= map->virt + map->size)
274620242aeSMyron Stowe 			return map;
275620242aeSMyron Stowe 
276620242aeSMyron Stowe 	return NULL;
277620242aeSMyron Stowe }
278620242aeSMyron Stowe 
279*214c2362SSunil V L #if defined(CONFIG_IA64) || defined(CONFIG_ARM64) || defined(CONFIG_RISCV)
280ba242d5bSMyron Stowe /* ioremap will take care of cache attributes */
281ba242d5bSMyron Stowe #define should_use_kmap(pfn)   0
282aafc65c7SGraeme Gregory #else
283aafc65c7SGraeme Gregory #define should_use_kmap(pfn)   page_is_ram(pfn)
284ba242d5bSMyron Stowe #endif
285ba242d5bSMyron Stowe 
acpi_map(acpi_physical_address pg_off,unsigned long pg_sz)28612064c17SJia He static void __iomem *acpi_map(acpi_physical_address pg_off, unsigned long pg_sz)
287ba242d5bSMyron Stowe {
288ba242d5bSMyron Stowe 	unsigned long pfn;
289ba242d5bSMyron Stowe 
290ba242d5bSMyron Stowe 	pfn = pg_off >> PAGE_SHIFT;
291ba242d5bSMyron Stowe 	if (should_use_kmap(pfn)) {
292ba242d5bSMyron Stowe 		if (pg_sz > PAGE_SIZE)
293ba242d5bSMyron Stowe 			return NULL;
294ba242d5bSMyron Stowe 		return (void __iomem __force *)kmap(pfn_to_page(pfn));
295ba242d5bSMyron Stowe 	} else
29612064c17SJia He 		return acpi_os_ioremap(pg_off, pg_sz);
297ba242d5bSMyron Stowe }
298ba242d5bSMyron Stowe 
acpi_unmap(acpi_physical_address pg_off,void __iomem * vaddr)299ba242d5bSMyron Stowe static void acpi_unmap(acpi_physical_address pg_off, void __iomem *vaddr)
300ba242d5bSMyron Stowe {
301ba242d5bSMyron Stowe 	unsigned long pfn;
302ba242d5bSMyron Stowe 
303ba242d5bSMyron Stowe 	pfn = pg_off >> PAGE_SHIFT;
304e252675fSJan Beulich 	if (should_use_kmap(pfn))
305ba242d5bSMyron Stowe 		kunmap(pfn_to_page(pfn));
306ba242d5bSMyron Stowe 	else
307ba242d5bSMyron Stowe 		iounmap(vaddr);
308ba242d5bSMyron Stowe }
309ba242d5bSMyron Stowe 
3109d128ed1SRafael J. Wysocki /**
31112064c17SJia He  * acpi_os_map_iomem - Get a virtual address for a given physical address range.
3129d128ed1SRafael J. Wysocki  * @phys: Start of the physical address range to map.
3139d128ed1SRafael J. Wysocki  * @size: Size of the physical address range to map.
3149d128ed1SRafael J. Wysocki  *
3159d128ed1SRafael J. Wysocki  * Look up the given physical address range in the list of existing ACPI memory
3169d128ed1SRafael J. Wysocki  * mappings.  If found, get a reference to it and return a pointer to it (its
3179d128ed1SRafael J. Wysocki  * virtual address).  If not found, map it, add it to that list and return a
3189d128ed1SRafael J. Wysocki  * pointer to it.
3199d128ed1SRafael J. Wysocki  *
3208d3523fbSLv Zheng  * During early init (when acpi_permanent_mmap has not been set yet) this
3219d128ed1SRafael J. Wysocki  * routine simply calls __acpi_map_table() to get the job done.
3229d128ed1SRafael J. Wysocki  */
32312064c17SJia He void __iomem __ref
acpi_os_map_iomem(acpi_physical_address phys,acpi_size size)32412064c17SJia He *acpi_os_map_iomem(acpi_physical_address phys, acpi_size size)
3251da177e4SLinus Torvalds {
3267ffd0443SRafael J. Wysocki 	struct acpi_ioremap *map;
327620242aeSMyron Stowe 	void __iomem *virt;
3282d6d9fd3SRafael J. Wysocki 	acpi_physical_address pg_off;
3292d6d9fd3SRafael J. Wysocki 	acpi_size pg_sz;
330620242aeSMyron Stowe 
3311da177e4SLinus Torvalds 	if (phys > ULONG_MAX) {
3328aef273eSRafael J. Wysocki 		pr_err("Cannot map memory that high: 0x%llx\n", phys);
33370c0846eSRandy Dunlap 		return NULL;
3341da177e4SLinus Torvalds 	}
335620242aeSMyron Stowe 
3368d3523fbSLv Zheng 	if (!acpi_permanent_mmap)
337ad71860aSAlexey Starikovskiy 		return __acpi_map_table((unsigned long)phys, size);
338620242aeSMyron Stowe 
3397ffd0443SRafael J. Wysocki 	mutex_lock(&acpi_ioremap_lock);
3407ffd0443SRafael J. Wysocki 	/* Check if there's a suitable mapping already. */
3417ffd0443SRafael J. Wysocki 	map = acpi_map_lookup(phys, size);
3427ffd0443SRafael J. Wysocki 	if (map) {
3431757659dSRafael J. Wysocki 		map->track.refcount++;
3447ffd0443SRafael J. Wysocki 		goto out;
3457ffd0443SRafael J. Wysocki 	}
3467ffd0443SRafael J. Wysocki 
347620242aeSMyron Stowe 	map = kzalloc(sizeof(*map), GFP_KERNEL);
3487ffd0443SRafael J. Wysocki 	if (!map) {
3497ffd0443SRafael J. Wysocki 		mutex_unlock(&acpi_ioremap_lock);
350620242aeSMyron Stowe 		return NULL;
3517ffd0443SRafael J. Wysocki 	}
352620242aeSMyron Stowe 
3534a3cba5eSMyron Stowe 	pg_off = round_down(phys, PAGE_SIZE);
3544a3cba5eSMyron Stowe 	pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off;
35512064c17SJia He 	virt = acpi_map(phys, size);
356620242aeSMyron Stowe 	if (!virt) {
3577ffd0443SRafael J. Wysocki 		mutex_unlock(&acpi_ioremap_lock);
358620242aeSMyron Stowe 		kfree(map);
359620242aeSMyron Stowe 		return NULL;
360620242aeSMyron Stowe 	}
361620242aeSMyron Stowe 
362620242aeSMyron Stowe 	INIT_LIST_HEAD(&map->list);
36317189d91SArd Biesheuvel 	map->virt = (void __iomem __force *)((unsigned long)virt & PAGE_MASK);
3644a3cba5eSMyron Stowe 	map->phys = pg_off;
3654a3cba5eSMyron Stowe 	map->size = pg_sz;
3661757659dSRafael J. Wysocki 	map->track.refcount = 1;
367620242aeSMyron Stowe 
36878cdb3edSMyron Stowe 	list_add_tail_rcu(&map->list, &acpi_ioremaps);
369620242aeSMyron Stowe 
3707ffd0443SRafael J. Wysocki out:
3717ffd0443SRafael J. Wysocki 	mutex_unlock(&acpi_ioremap_lock);
3724a3cba5eSMyron Stowe 	return map->virt + (phys - map->phys);
3731da177e4SLinus Torvalds }
374a238317cSLv Zheng EXPORT_SYMBOL_GPL(acpi_os_map_iomem);
375a238317cSLv Zheng 
acpi_os_map_memory(acpi_physical_address phys,acpi_size size)376bd721ea7SFabian Frederick void *__ref acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
377a238317cSLv Zheng {
37812064c17SJia He 	return (void *)acpi_os_map_iomem(phys, size);
379a238317cSLv Zheng }
38055a82ab3SKylene Jo Hall EXPORT_SYMBOL_GPL(acpi_os_map_memory);
3811da177e4SLinus Torvalds 
acpi_os_map_remove(struct work_struct * work)3825003ad71SRafael J. Wysocki static void acpi_os_map_remove(struct work_struct *work)
3834a3cba5eSMyron Stowe {
3845003ad71SRafael J. Wysocki 	struct acpi_ioremap *map = container_of(to_rcu_work(work),
3855003ad71SRafael J. Wysocki 						struct acpi_ioremap,
3865003ad71SRafael J. Wysocki 						track.rwork);
3875003ad71SRafael J. Wysocki 
3881757659dSRafael J. Wysocki 	acpi_unmap(map->phys, map->virt);
3891757659dSRafael J. Wysocki 	kfree(map);
3901757659dSRafael J. Wysocki }
391833a426cSFrancesco Ruggeri 
3921757659dSRafael J. Wysocki /* Must be called with mutex_lock(&acpi_ioremap_lock) */
acpi_os_drop_map_ref(struct acpi_ioremap * map)393a968fba2SRafael J. Wysocki static void acpi_os_drop_map_ref(struct acpi_ioremap *map)
3941757659dSRafael J. Wysocki {
3951757659dSRafael J. Wysocki 	if (--map->track.refcount)
396a968fba2SRafael J. Wysocki 		return;
3971757659dSRafael J. Wysocki 
3984a3cba5eSMyron Stowe 	list_del_rcu(&map->list);
3991757659dSRafael J. Wysocki 
4005003ad71SRafael J. Wysocki 	INIT_RCU_WORK(&map->track.rwork, acpi_os_map_remove);
4011757659dSRafael J. Wysocki 	queue_rcu_work(system_wq, &map->track.rwork);
4021757659dSRafael J. Wysocki }
4034a3cba5eSMyron Stowe 
404a968fba2SRafael J. Wysocki /**
405a968fba2SRafael J. Wysocki  * acpi_os_unmap_iomem - Drop a memory mapping reference.
406a968fba2SRafael J. Wysocki  * @virt: Start of the address range to drop a reference to.
407a968fba2SRafael J. Wysocki  * @size: Size of the address range to drop a reference to.
408a968fba2SRafael J. Wysocki  *
409a968fba2SRafael J. Wysocki  * Look up the given virtual address range in the list of existing ACPI memory
410a968fba2SRafael J. Wysocki  * mappings, drop a reference to it and if there are no more active references
411a968fba2SRafael J. Wysocki  * to it, queue it up for later removal.
412a968fba2SRafael J. Wysocki  *
413a968fba2SRafael J. Wysocki  * During early init (when acpi_permanent_mmap has not been set yet) this
414a968fba2SRafael J. Wysocki  * routine simply calls __acpi_unmap_table() to get the job done.  Since
415a968fba2SRafael J. Wysocki  * __acpi_unmap_table() is an __init function, the __ref annotation is needed
416a968fba2SRafael J. Wysocki  * here.
417a968fba2SRafael J. Wysocki  */
acpi_os_unmap_iomem(void __iomem * virt,acpi_size size)418a968fba2SRafael J. Wysocki void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size)
4191757659dSRafael J. Wysocki {
4201757659dSRafael J. Wysocki 	struct acpi_ioremap *map;
4211757659dSRafael J. Wysocki 
4221757659dSRafael J. Wysocki 	if (!acpi_permanent_mmap) {
4231757659dSRafael J. Wysocki 		__acpi_unmap_table(virt, size);
4241757659dSRafael J. Wysocki 		return;
4251757659dSRafael J. Wysocki 	}
4261757659dSRafael J. Wysocki 
4271757659dSRafael J. Wysocki 	mutex_lock(&acpi_ioremap_lock);
4281757659dSRafael J. Wysocki 
4291757659dSRafael J. Wysocki 	map = acpi_map_lookup_virt(virt, size);
4301757659dSRafael J. Wysocki 	if (!map) {
4311757659dSRafael J. Wysocki 		mutex_unlock(&acpi_ioremap_lock);
4322e670dedSHanjun Guo 		WARN(true, "ACPI: %s: bad address %p\n", __func__, virt);
4331757659dSRafael J. Wysocki 		return;
4341757659dSRafael J. Wysocki 	}
435a968fba2SRafael J. Wysocki 	acpi_os_drop_map_ref(map);
4361757659dSRafael J. Wysocki 
4371757659dSRafael J. Wysocki 	mutex_unlock(&acpi_ioremap_lock);
438ad71860aSAlexey Starikovskiy }
439a238317cSLv Zheng EXPORT_SYMBOL_GPL(acpi_os_unmap_iomem);
440a238317cSLv Zheng 
4411757659dSRafael J. Wysocki /**
4421757659dSRafael J. Wysocki  * acpi_os_unmap_memory - Drop a memory mapping reference.
4431757659dSRafael J. Wysocki  * @virt: Start of the address range to drop a reference to.
4441757659dSRafael J. Wysocki  * @size: Size of the address range to drop a reference to.
4451757659dSRafael J. Wysocki  */
acpi_os_unmap_memory(void * virt,acpi_size size)446a238317cSLv Zheng void __ref acpi_os_unmap_memory(void *virt, acpi_size size)
447a238317cSLv Zheng {
448a968fba2SRafael J. Wysocki 	acpi_os_unmap_iomem((void __iomem *)virt, size);
449a238317cSLv Zheng }
45055a82ab3SKylene Jo Hall EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
4511da177e4SLinus Torvalds 
acpi_os_map_generic_address(struct acpi_generic_address * gas)4526915564dSRafael J. Wysocki void __iomem *acpi_os_map_generic_address(struct acpi_generic_address *gas)
45329718521SMyron Stowe {
454bc9ffce2SMyron Stowe 	u64 addr;
45529718521SMyron Stowe 
456bc9ffce2SMyron Stowe 	if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
4576915564dSRafael J. Wysocki 		return NULL;
45829718521SMyron Stowe 
459bc9ffce2SMyron Stowe 	/* Handle possible alignment issues */
460bc9ffce2SMyron Stowe 	memcpy(&addr, &gas->address, sizeof(addr));
461bc9ffce2SMyron Stowe 	if (!addr || !gas->bit_width)
4626915564dSRafael J. Wysocki 		return NULL;
46329718521SMyron Stowe 
4646915564dSRafael J. Wysocki 	return acpi_os_map_iomem(addr, gas->bit_width / 8);
46529718521SMyron Stowe }
4666f68c91cSMyron Stowe EXPORT_SYMBOL(acpi_os_map_generic_address);
46729718521SMyron Stowe 
acpi_os_unmap_generic_address(struct acpi_generic_address * gas)4686f68c91cSMyron Stowe void acpi_os_unmap_generic_address(struct acpi_generic_address *gas)
46929718521SMyron Stowe {
470bc9ffce2SMyron Stowe 	u64 addr;
4717fe135dcSRafael J. Wysocki 	struct acpi_ioremap *map;
47229718521SMyron Stowe 
473bc9ffce2SMyron Stowe 	if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
47429718521SMyron Stowe 		return;
47529718521SMyron Stowe 
476bc9ffce2SMyron Stowe 	/* Handle possible alignment issues */
477bc9ffce2SMyron Stowe 	memcpy(&addr, &gas->address, sizeof(addr));
478bc9ffce2SMyron Stowe 	if (!addr || !gas->bit_width)
47929718521SMyron Stowe 		return;
48029718521SMyron Stowe 
4817bbb8903SRafael J. Wysocki 	mutex_lock(&acpi_ioremap_lock);
4821757659dSRafael J. Wysocki 
483bc9ffce2SMyron Stowe 	map = acpi_map_lookup(addr, gas->bit_width / 8);
4847fe135dcSRafael J. Wysocki 	if (!map) {
4857fe135dcSRafael J. Wysocki 		mutex_unlock(&acpi_ioremap_lock);
4867fe135dcSRafael J. Wysocki 		return;
48729718521SMyron Stowe 	}
488a968fba2SRafael J. Wysocki 	acpi_os_drop_map_ref(map);
4891757659dSRafael J. Wysocki 
4907bbb8903SRafael J. Wysocki 	mutex_unlock(&acpi_ioremap_lock);
49129718521SMyron Stowe }
4926f68c91cSMyron Stowe EXPORT_SYMBOL(acpi_os_unmap_generic_address);
49329718521SMyron Stowe 
4941da177e4SLinus Torvalds #ifdef ACPI_FUTURE_USAGE
4951da177e4SLinus Torvalds acpi_status
acpi_os_get_physical_address(void * virt,acpi_physical_address * phys)4961da177e4SLinus Torvalds acpi_os_get_physical_address(void *virt, acpi_physical_address * phys)
4971da177e4SLinus Torvalds {
4981da177e4SLinus Torvalds 	if (!phys || !virt)
4991da177e4SLinus Torvalds 		return AE_BAD_PARAMETER;
5001da177e4SLinus Torvalds 
5011da177e4SLinus Torvalds 	*phys = virt_to_phys(virt);
5021da177e4SLinus Torvalds 
5031da177e4SLinus Torvalds 	return AE_OK;
5041da177e4SLinus Torvalds }
5051da177e4SLinus Torvalds #endif
5061da177e4SLinus Torvalds 
50718d78b64SRafael J. Wysocki #ifdef CONFIG_ACPI_REV_OVERRIDE_POSSIBLE
50818d78b64SRafael J. Wysocki static bool acpi_rev_override;
50918d78b64SRafael J. Wysocki 
acpi_rev_override_setup(char * str)51018d78b64SRafael J. Wysocki int __init acpi_rev_override_setup(char *str)
51118d78b64SRafael J. Wysocki {
51218d78b64SRafael J. Wysocki 	acpi_rev_override = true;
51318d78b64SRafael J. Wysocki 	return 1;
51418d78b64SRafael J. Wysocki }
51518d78b64SRafael J. Wysocki __setup("acpi_rev_override", acpi_rev_override_setup);
51618d78b64SRafael J. Wysocki #else
51718d78b64SRafael J. Wysocki #define acpi_rev_override	false
51818d78b64SRafael J. Wysocki #endif
51918d78b64SRafael J. Wysocki 
5201da177e4SLinus Torvalds #define ACPI_MAX_OVERRIDE_LEN 100
5211da177e4SLinus Torvalds 
5221da177e4SLinus Torvalds static char acpi_os_name[ACPI_MAX_OVERRIDE_LEN];
5231da177e4SLinus Torvalds 
5241da177e4SLinus Torvalds acpi_status
acpi_os_predefined_override(const struct acpi_predefined_names * init_val,acpi_string * new_val)5251da177e4SLinus Torvalds acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
52680b28810SLv Zheng 			    acpi_string *new_val)
5271da177e4SLinus Torvalds {
5281da177e4SLinus Torvalds 	if (!init_val || !new_val)
5291da177e4SLinus Torvalds 		return AE_BAD_PARAMETER;
5301da177e4SLinus Torvalds 
5311da177e4SLinus Torvalds 	*new_val = NULL;
5321da177e4SLinus Torvalds 	if (!memcmp(init_val->name, "_OS_", 4) && strlen(acpi_os_name)) {
5338aef273eSRafael J. Wysocki 		pr_info("Overriding _OS definition to '%s'\n", acpi_os_name);
5341da177e4SLinus Torvalds 		*new_val = acpi_os_name;
5351da177e4SLinus Torvalds 	}
5361da177e4SLinus Torvalds 
53718d78b64SRafael J. Wysocki 	if (!memcmp(init_val->name, "_REV", 4) && acpi_rev_override) {
5388aef273eSRafael J. Wysocki 		pr_info("Overriding _REV return value to 5\n");
53918d78b64SRafael J. Wysocki 		*new_val = (char *)5;
54018d78b64SRafael J. Wysocki 	}
54118d78b64SRafael J. Wysocki 
5421da177e4SLinus Torvalds 	return AE_OK;
5431da177e4SLinus Torvalds }
5441da177e4SLinus Torvalds 
acpi_irq(int irq,void * dev_id)5457d12e780SDavid Howells static irqreturn_t acpi_irq(int irq, void *dev_id)
5461da177e4SLinus Torvalds {
5475229e87dSLen Brown 	u32 handled;
5485229e87dSLen Brown 
5495229e87dSLen Brown 	handled = (*acpi_irq_handler) (acpi_irq_context);
5505229e87dSLen Brown 
5515229e87dSLen Brown 	if (handled) {
5525229e87dSLen Brown 		acpi_irq_handled++;
5535229e87dSLen Brown 		return IRQ_HANDLED;
55488bea188SLen Brown 	} else {
55588bea188SLen Brown 		acpi_irq_not_handled++;
5565229e87dSLen Brown 		return IRQ_NONE;
5571da177e4SLinus Torvalds 	}
55888bea188SLen Brown }
5591da177e4SLinus Torvalds 
5601da177e4SLinus Torvalds acpi_status
acpi_os_install_interrupt_handler(u32 gsi,acpi_osd_handler handler,void * context)5614be44fcdSLen Brown acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
5624be44fcdSLen Brown 				  void *context)
5631da177e4SLinus Torvalds {
5641da177e4SLinus Torvalds 	unsigned int irq;
5651da177e4SLinus Torvalds 
5665229e87dSLen Brown 	acpi_irq_stats_init();
5675229e87dSLen Brown 
5681da177e4SLinus Torvalds 	/*
56923fe3630SRafael J. Wysocki 	 * ACPI interrupts different from the SCI in our copy of the FADT are
57023fe3630SRafael J. Wysocki 	 * not supported.
5711da177e4SLinus Torvalds 	 */
57223fe3630SRafael J. Wysocki 	if (gsi != acpi_gbl_FADT.sci_interrupt)
57323fe3630SRafael J. Wysocki 		return AE_BAD_PARAMETER;
57423fe3630SRafael J. Wysocki 
57523fe3630SRafael J. Wysocki 	if (acpi_irq_handler)
57623fe3630SRafael J. Wysocki 		return AE_ALREADY_ACQUIRED;
57723fe3630SRafael J. Wysocki 
5781da177e4SLinus Torvalds 	if (acpi_gsi_to_irq(gsi, &irq) < 0) {
5798aef273eSRafael J. Wysocki 		pr_err("SCI (ACPI GSI %d) not registered\n", gsi);
5801da177e4SLinus Torvalds 		return AE_OK;
5811da177e4SLinus Torvalds 	}
5821da177e4SLinus Torvalds 
5831da177e4SLinus Torvalds 	acpi_irq_handler = handler;
5841da177e4SLinus Torvalds 	acpi_irq_context = context;
585a8d46b9eSRafael J. Wysocki 	if (request_irq(irq, acpi_irq, IRQF_SHARED, "acpi", acpi_irq)) {
5868aef273eSRafael J. Wysocki 		pr_err("SCI (IRQ%d) allocation failed\n", irq);
58723fe3630SRafael J. Wysocki 		acpi_irq_handler = NULL;
5881da177e4SLinus Torvalds 		return AE_NOT_ACQUIRED;
5891da177e4SLinus Torvalds 	}
59049e4b843SChen Yu 	acpi_sci_irq = irq;
5911da177e4SLinus Torvalds 
5921da177e4SLinus Torvalds 	return AE_OK;
5931da177e4SLinus Torvalds }
5941da177e4SLinus Torvalds 
acpi_os_remove_interrupt_handler(u32 gsi,acpi_osd_handler handler)59549e4b843SChen Yu acpi_status acpi_os_remove_interrupt_handler(u32 gsi, acpi_osd_handler handler)
5961da177e4SLinus Torvalds {
59749e4b843SChen Yu 	if (gsi != acpi_gbl_FADT.sci_interrupt || !acpi_sci_irq_valid())
59823fe3630SRafael J. Wysocki 		return AE_BAD_PARAMETER;
59923fe3630SRafael J. Wysocki 
60049e4b843SChen Yu 	free_irq(acpi_sci_irq, acpi_irq);
6011da177e4SLinus Torvalds 	acpi_irq_handler = NULL;
60249e4b843SChen Yu 	acpi_sci_irq = INVALID_ACPI_IRQ;
6031da177e4SLinus Torvalds 
6041da177e4SLinus Torvalds 	return AE_OK;
6051da177e4SLinus Torvalds }
6061da177e4SLinus Torvalds 
6071da177e4SLinus Torvalds /*
6081da177e4SLinus Torvalds  * Running in interpreter thread context, safe to sleep
6091da177e4SLinus Torvalds  */
6101da177e4SLinus Torvalds 
acpi_os_sleep(u64 ms)611439913ffSLin Ming void acpi_os_sleep(u64 ms)
6121da177e4SLinus Torvalds {
61330282299SLiu Chuansheng 	msleep(ms);
6141da177e4SLinus Torvalds }
6154be44fcdSLen Brown 
acpi_os_stall(u32 us)6164be44fcdSLen Brown void acpi_os_stall(u32 us)
6171da177e4SLinus Torvalds {
6181da177e4SLinus Torvalds 	while (us) {
6191da177e4SLinus Torvalds 		u32 delay = 1000;
6201da177e4SLinus Torvalds 
6211da177e4SLinus Torvalds 		if (delay > us)
6221da177e4SLinus Torvalds 			delay = us;
6231da177e4SLinus Torvalds 		udelay(delay);
6241da177e4SLinus Torvalds 		touch_nmi_watchdog();
6251da177e4SLinus Torvalds 		us -= delay;
6261da177e4SLinus Torvalds 	}
6271da177e4SLinus Torvalds }
6284be44fcdSLen Brown 
6291da177e4SLinus Torvalds /*
63083b2348eSBart Van Assche  * Support ACPI 3.0 AML Timer operand. Returns a 64-bit free-running,
63183b2348eSBart Van Assche  * monotonically increasing timer with 100ns granularity. Do not use
63283b2348eSBart Van Assche  * ktime_get() to implement this function because this function may get
63383b2348eSBart Van Assche  * called after timekeeping has been suspended. Note: calling this function
63483b2348eSBart Van Assche  * after timekeeping has been suspended may lead to unexpected results
63583b2348eSBart Van Assche  * because when timekeeping is suspended the jiffies counter is not
63683b2348eSBart Van Assche  * incremented. See also timekeeping_suspend().
6371da177e4SLinus Torvalds  */
acpi_os_get_timer(void)6384be44fcdSLen Brown u64 acpi_os_get_timer(void)
6391da177e4SLinus Torvalds {
64083b2348eSBart Van Assche 	return (get_jiffies_64() - INITIAL_JIFFIES) *
64183b2348eSBart Van Assche 		(ACPI_100NSEC_PER_SEC / HZ);
6421da177e4SLinus Torvalds }
6431da177e4SLinus Torvalds 
acpi_os_read_port(acpi_io_address port,u32 * value,u32 width)6444be44fcdSLen Brown acpi_status acpi_os_read_port(acpi_io_address port, u32 *value, u32 width)
6451da177e4SLinus Torvalds {
6461da177e4SLinus Torvalds 	u32 dummy;
6471da177e4SLinus Torvalds 
6482e433a94SRafael J. Wysocki 	if (value)
6492e433a94SRafael J. Wysocki 		*value = 0;
6502e433a94SRafael J. Wysocki 	else
6511da177e4SLinus Torvalds 		value = &dummy;
6521da177e4SLinus Torvalds 
65349fbabf5SZhao Yakui 	if (width <= 8) {
6542e433a94SRafael J. Wysocki 		*value = inb(port);
65549fbabf5SZhao Yakui 	} else if (width <= 16) {
6562e433a94SRafael J. Wysocki 		*value = inw(port);
65749fbabf5SZhao Yakui 	} else if (width <= 32) {
6582e433a94SRafael J. Wysocki 		*value = inl(port);
65949fbabf5SZhao Yakui 	} else {
6602e433a94SRafael J. Wysocki 		pr_debug("%s: Access width %d not supported\n", __func__, width);
6612e433a94SRafael J. Wysocki 		return AE_BAD_PARAMETER;
6621da177e4SLinus Torvalds 	}
6631da177e4SLinus Torvalds 
6641da177e4SLinus Torvalds 	return AE_OK;
6651da177e4SLinus Torvalds }
6664be44fcdSLen Brown 
6671da177e4SLinus Torvalds EXPORT_SYMBOL(acpi_os_read_port);
6681da177e4SLinus Torvalds 
acpi_os_write_port(acpi_io_address port,u32 value,u32 width)6694be44fcdSLen Brown acpi_status acpi_os_write_port(acpi_io_address port, u32 value, u32 width)
6701da177e4SLinus Torvalds {
67149fbabf5SZhao Yakui 	if (width <= 8) {
6721da177e4SLinus Torvalds 		outb(value, port);
67349fbabf5SZhao Yakui 	} else if (width <= 16) {
6741da177e4SLinus Torvalds 		outw(value, port);
67549fbabf5SZhao Yakui 	} else if (width <= 32) {
6761da177e4SLinus Torvalds 		outl(value, port);
67749fbabf5SZhao Yakui 	} else {
6782e433a94SRafael J. Wysocki 		pr_debug("%s: Access width %d not supported\n", __func__, width);
6792e433a94SRafael J. Wysocki 		return AE_BAD_PARAMETER;
6801da177e4SLinus Torvalds 	}
6811da177e4SLinus Torvalds 
6821da177e4SLinus Torvalds 	return AE_OK;
6831da177e4SLinus Torvalds }
6844be44fcdSLen Brown 
6851da177e4SLinus Torvalds EXPORT_SYMBOL(acpi_os_write_port);
6861da177e4SLinus Torvalds 
acpi_os_read_iomem(void __iomem * virt_addr,u64 * value,u32 width)687eeb2d80dSSrinivas Pandruvada int acpi_os_read_iomem(void __iomem *virt_addr, u64 *value, u32 width)
688e615bf5bSMyron Stowe {
689e615bf5bSMyron Stowe 
690e615bf5bSMyron Stowe 	switch (width) {
691e615bf5bSMyron Stowe 	case 8:
692e615bf5bSMyron Stowe 		*(u8 *) value = readb(virt_addr);
693e615bf5bSMyron Stowe 		break;
694e615bf5bSMyron Stowe 	case 16:
695e615bf5bSMyron Stowe 		*(u16 *) value = readw(virt_addr);
696e615bf5bSMyron Stowe 		break;
697e615bf5bSMyron Stowe 	case 32:
698e615bf5bSMyron Stowe 		*(u32 *) value = readl(virt_addr);
699e615bf5bSMyron Stowe 		break;
700e615bf5bSMyron Stowe 	case 64:
7013277b4eaSAndy Shevchenko 		*(u64 *) value = readq(virt_addr);
702e615bf5bSMyron Stowe 		break;
703e615bf5bSMyron Stowe 	default:
704eeb2d80dSSrinivas Pandruvada 		return -EINVAL;
705e615bf5bSMyron Stowe 	}
706e615bf5bSMyron Stowe 
707eeb2d80dSSrinivas Pandruvada 	return 0;
708eeb2d80dSSrinivas Pandruvada }
709eeb2d80dSSrinivas Pandruvada 
710eeb2d80dSSrinivas Pandruvada acpi_status
acpi_os_read_memory(acpi_physical_address phys_addr,u64 * value,u32 width)711eeb2d80dSSrinivas Pandruvada acpi_os_read_memory(acpi_physical_address phys_addr, u64 *value, u32 width)
712eeb2d80dSSrinivas Pandruvada {
713eeb2d80dSSrinivas Pandruvada 	void __iomem *virt_addr;
714eeb2d80dSSrinivas Pandruvada 	unsigned int size = width / 8;
715eeb2d80dSSrinivas Pandruvada 	bool unmap = false;
716eeb2d80dSSrinivas Pandruvada 	u64 dummy;
717eeb2d80dSSrinivas Pandruvada 	int error;
718eeb2d80dSSrinivas Pandruvada 
719eeb2d80dSSrinivas Pandruvada 	rcu_read_lock();
720eeb2d80dSSrinivas Pandruvada 	virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
721eeb2d80dSSrinivas Pandruvada 	if (!virt_addr) {
722eeb2d80dSSrinivas Pandruvada 		rcu_read_unlock();
723eeb2d80dSSrinivas Pandruvada 		virt_addr = acpi_os_ioremap(phys_addr, size);
724eeb2d80dSSrinivas Pandruvada 		if (!virt_addr)
725eeb2d80dSSrinivas Pandruvada 			return AE_BAD_ADDRESS;
726eeb2d80dSSrinivas Pandruvada 		unmap = true;
727eeb2d80dSSrinivas Pandruvada 	}
728eeb2d80dSSrinivas Pandruvada 
729eeb2d80dSSrinivas Pandruvada 	if (!value)
730eeb2d80dSSrinivas Pandruvada 		value = &dummy;
731eeb2d80dSSrinivas Pandruvada 
732eeb2d80dSSrinivas Pandruvada 	error = acpi_os_read_iomem(virt_addr, value, width);
733eeb2d80dSSrinivas Pandruvada 	BUG_ON(error);
734eeb2d80dSSrinivas Pandruvada 
735e615bf5bSMyron Stowe 	if (unmap)
736e615bf5bSMyron Stowe 		iounmap(virt_addr);
737e615bf5bSMyron Stowe 	else
738e615bf5bSMyron Stowe 		rcu_read_unlock();
739e615bf5bSMyron Stowe 
740e615bf5bSMyron Stowe 	return AE_OK;
741e615bf5bSMyron Stowe }
742e615bf5bSMyron Stowe 
743e615bf5bSMyron Stowe acpi_status
acpi_os_write_memory(acpi_physical_address phys_addr,u64 value,u32 width)744653f4b53SBob Moore acpi_os_write_memory(acpi_physical_address phys_addr, u64 value, u32 width)
745e615bf5bSMyron Stowe {
746e615bf5bSMyron Stowe 	void __iomem *virt_addr;
747e615bf5bSMyron Stowe 	unsigned int size = width / 8;
748e615bf5bSMyron Stowe 	bool unmap = false;
749e615bf5bSMyron Stowe 
750e615bf5bSMyron Stowe 	rcu_read_lock();
751e615bf5bSMyron Stowe 	virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
752e615bf5bSMyron Stowe 	if (!virt_addr) {
753e615bf5bSMyron Stowe 		rcu_read_unlock();
754e615bf5bSMyron Stowe 		virt_addr = acpi_os_ioremap(phys_addr, size);
755e615bf5bSMyron Stowe 		if (!virt_addr)
756e615bf5bSMyron Stowe 			return AE_BAD_ADDRESS;
757e615bf5bSMyron Stowe 		unmap = true;
758e615bf5bSMyron Stowe 	}
759e615bf5bSMyron Stowe 
760e615bf5bSMyron Stowe 	switch (width) {
761e615bf5bSMyron Stowe 	case 8:
762e615bf5bSMyron Stowe 		writeb(value, virt_addr);
763e615bf5bSMyron Stowe 		break;
764e615bf5bSMyron Stowe 	case 16:
765e615bf5bSMyron Stowe 		writew(value, virt_addr);
766e615bf5bSMyron Stowe 		break;
767e615bf5bSMyron Stowe 	case 32:
768e615bf5bSMyron Stowe 		writel(value, virt_addr);
769e615bf5bSMyron Stowe 		break;
770e615bf5bSMyron Stowe 	case 64:
7713277b4eaSAndy Shevchenko 		writeq(value, virt_addr);
772e615bf5bSMyron Stowe 		break;
773e615bf5bSMyron Stowe 	default:
774e615bf5bSMyron Stowe 		BUG();
775e615bf5bSMyron Stowe 	}
776e615bf5bSMyron Stowe 
777e615bf5bSMyron Stowe 	if (unmap)
778e615bf5bSMyron Stowe 		iounmap(virt_addr);
779e615bf5bSMyron Stowe 	else
780e615bf5bSMyron Stowe 		rcu_read_unlock();
781e615bf5bSMyron Stowe 
782e615bf5bSMyron Stowe 	return AE_OK;
783e615bf5bSMyron Stowe }
784e615bf5bSMyron Stowe 
785bd23fac3SSinan Kaya #ifdef CONFIG_PCI
7861da177e4SLinus Torvalds acpi_status
acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id,u32 reg,u64 * value,u32 width)7874be44fcdSLen Brown acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
788c5f0231eSBob Moore 			       u64 *value, u32 width)
7891da177e4SLinus Torvalds {
7901da177e4SLinus Torvalds 	int result, size;
791c5f0231eSBob Moore 	u32 value32;
7921da177e4SLinus Torvalds 
7931da177e4SLinus Torvalds 	if (!value)
7941da177e4SLinus Torvalds 		return AE_BAD_PARAMETER;
7951da177e4SLinus Torvalds 
7961da177e4SLinus Torvalds 	switch (width) {
7971da177e4SLinus Torvalds 	case 8:
7981da177e4SLinus Torvalds 		size = 1;
7991da177e4SLinus Torvalds 		break;
8001da177e4SLinus Torvalds 	case 16:
8011da177e4SLinus Torvalds 		size = 2;
8021da177e4SLinus Torvalds 		break;
8031da177e4SLinus Torvalds 	case 32:
8041da177e4SLinus Torvalds 		size = 4;
8051da177e4SLinus Torvalds 		break;
8061da177e4SLinus Torvalds 	default:
8071da177e4SLinus Torvalds 		return AE_ERROR;
8081da177e4SLinus Torvalds 	}
8091da177e4SLinus Torvalds 
810b6ce068aSMatthew Wilcox 	result = raw_pci_read(pci_id->segment, pci_id->bus,
8111da177e4SLinus Torvalds 				PCI_DEVFN(pci_id->device, pci_id->function),
812c5f0231eSBob Moore 				reg, size, &value32);
813c5f0231eSBob Moore 	*value = value32;
8141da177e4SLinus Torvalds 
8151da177e4SLinus Torvalds 	return (result ? AE_ERROR : AE_OK);
8161da177e4SLinus Torvalds }
8174be44fcdSLen Brown 
8181da177e4SLinus Torvalds acpi_status
acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id,u32 reg,u64 value,u32 width)8194be44fcdSLen Brown acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
820439913ffSLin Ming 				u64 value, u32 width)
8211da177e4SLinus Torvalds {
8221da177e4SLinus Torvalds 	int result, size;
8231da177e4SLinus Torvalds 
8241da177e4SLinus Torvalds 	switch (width) {
8251da177e4SLinus Torvalds 	case 8:
8261da177e4SLinus Torvalds 		size = 1;
8271da177e4SLinus Torvalds 		break;
8281da177e4SLinus Torvalds 	case 16:
8291da177e4SLinus Torvalds 		size = 2;
8301da177e4SLinus Torvalds 		break;
8311da177e4SLinus Torvalds 	case 32:
8321da177e4SLinus Torvalds 		size = 4;
8331da177e4SLinus Torvalds 		break;
8341da177e4SLinus Torvalds 	default:
8351da177e4SLinus Torvalds 		return AE_ERROR;
8361da177e4SLinus Torvalds 	}
8371da177e4SLinus Torvalds 
838b6ce068aSMatthew Wilcox 	result = raw_pci_write(pci_id->segment, pci_id->bus,
8391da177e4SLinus Torvalds 				PCI_DEVFN(pci_id->device, pci_id->function),
8401da177e4SLinus Torvalds 				reg, size, value);
8411da177e4SLinus Torvalds 
8421da177e4SLinus Torvalds 	return (result ? AE_ERROR : AE_OK);
8431da177e4SLinus Torvalds }
844bd23fac3SSinan Kaya #endif
8451da177e4SLinus Torvalds 
acpi_os_execute_deferred(struct work_struct * work)84665f27f38SDavid Howells static void acpi_os_execute_deferred(struct work_struct *work)
8471da177e4SLinus Torvalds {
84865f27f38SDavid Howells 	struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
84988db5e14SAlexey Starikovskiy 
85019cd847aSZhang Rui 	dpc->function(dpc->context);
85119cd847aSZhang Rui 	kfree(dpc);
85219cd847aSZhang Rui }
85319cd847aSZhang Rui 
854836d0830SLv Zheng #ifdef CONFIG_ACPI_DEBUGGER
855836d0830SLv Zheng static struct acpi_debugger acpi_debugger;
856836d0830SLv Zheng static bool acpi_debugger_initialized;
857836d0830SLv Zheng 
acpi_register_debugger(struct module * owner,const struct acpi_debugger_ops * ops)858836d0830SLv Zheng int acpi_register_debugger(struct module *owner,
859836d0830SLv Zheng 			   const struct acpi_debugger_ops *ops)
860836d0830SLv Zheng {
861836d0830SLv Zheng 	int ret = 0;
862836d0830SLv Zheng 
863836d0830SLv Zheng 	mutex_lock(&acpi_debugger.lock);
864836d0830SLv Zheng 	if (acpi_debugger.ops) {
865836d0830SLv Zheng 		ret = -EBUSY;
866836d0830SLv Zheng 		goto err_lock;
867836d0830SLv Zheng 	}
868836d0830SLv Zheng 
869836d0830SLv Zheng 	acpi_debugger.owner = owner;
870836d0830SLv Zheng 	acpi_debugger.ops = ops;
871836d0830SLv Zheng 
872836d0830SLv Zheng err_lock:
873836d0830SLv Zheng 	mutex_unlock(&acpi_debugger.lock);
874836d0830SLv Zheng 	return ret;
875836d0830SLv Zheng }
876836d0830SLv Zheng EXPORT_SYMBOL(acpi_register_debugger);
877836d0830SLv Zheng 
acpi_unregister_debugger(const struct acpi_debugger_ops * ops)878836d0830SLv Zheng void acpi_unregister_debugger(const struct acpi_debugger_ops *ops)
879836d0830SLv Zheng {
880836d0830SLv Zheng 	mutex_lock(&acpi_debugger.lock);
881836d0830SLv Zheng 	if (ops == acpi_debugger.ops) {
882836d0830SLv Zheng 		acpi_debugger.ops = NULL;
883836d0830SLv Zheng 		acpi_debugger.owner = NULL;
884836d0830SLv Zheng 	}
885836d0830SLv Zheng 	mutex_unlock(&acpi_debugger.lock);
886836d0830SLv Zheng }
887836d0830SLv Zheng EXPORT_SYMBOL(acpi_unregister_debugger);
888836d0830SLv Zheng 
acpi_debugger_create_thread(acpi_osd_exec_callback function,void * context)889836d0830SLv Zheng int acpi_debugger_create_thread(acpi_osd_exec_callback function, void *context)
890836d0830SLv Zheng {
891836d0830SLv Zheng 	int ret;
892836d0830SLv Zheng 	int (*func)(acpi_osd_exec_callback, void *);
893836d0830SLv Zheng 	struct module *owner;
894836d0830SLv Zheng 
895836d0830SLv Zheng 	if (!acpi_debugger_initialized)
896836d0830SLv Zheng 		return -ENODEV;
897836d0830SLv Zheng 	mutex_lock(&acpi_debugger.lock);
898836d0830SLv Zheng 	if (!acpi_debugger.ops) {
899836d0830SLv Zheng 		ret = -ENODEV;
900836d0830SLv Zheng 		goto err_lock;
901836d0830SLv Zheng 	}
902836d0830SLv Zheng 	if (!try_module_get(acpi_debugger.owner)) {
903836d0830SLv Zheng 		ret = -ENODEV;
904836d0830SLv Zheng 		goto err_lock;
905836d0830SLv Zheng 	}
906836d0830SLv Zheng 	func = acpi_debugger.ops->create_thread;
907836d0830SLv Zheng 	owner = acpi_debugger.owner;
908836d0830SLv Zheng 	mutex_unlock(&acpi_debugger.lock);
909836d0830SLv Zheng 
910836d0830SLv Zheng 	ret = func(function, context);
911836d0830SLv Zheng 
912836d0830SLv Zheng 	mutex_lock(&acpi_debugger.lock);
913836d0830SLv Zheng 	module_put(owner);
914836d0830SLv Zheng err_lock:
915836d0830SLv Zheng 	mutex_unlock(&acpi_debugger.lock);
916836d0830SLv Zheng 	return ret;
917836d0830SLv Zheng }
918836d0830SLv Zheng 
acpi_debugger_write_log(const char * msg)919836d0830SLv Zheng ssize_t acpi_debugger_write_log(const char *msg)
920836d0830SLv Zheng {
921836d0830SLv Zheng 	ssize_t ret;
922836d0830SLv Zheng 	ssize_t (*func)(const char *);
923836d0830SLv Zheng 	struct module *owner;
924836d0830SLv Zheng 
925836d0830SLv Zheng 	if (!acpi_debugger_initialized)
926836d0830SLv Zheng 		return -ENODEV;
927836d0830SLv Zheng 	mutex_lock(&acpi_debugger.lock);
928836d0830SLv Zheng 	if (!acpi_debugger.ops) {
929836d0830SLv Zheng 		ret = -ENODEV;
930836d0830SLv Zheng 		goto err_lock;
931836d0830SLv Zheng 	}
932836d0830SLv Zheng 	if (!try_module_get(acpi_debugger.owner)) {
933836d0830SLv Zheng 		ret = -ENODEV;
934836d0830SLv Zheng 		goto err_lock;
935836d0830SLv Zheng 	}
936836d0830SLv Zheng 	func = acpi_debugger.ops->write_log;
937836d0830SLv Zheng 	owner = acpi_debugger.owner;
938836d0830SLv Zheng 	mutex_unlock(&acpi_debugger.lock);
939836d0830SLv Zheng 
940836d0830SLv Zheng 	ret = func(msg);
941836d0830SLv Zheng 
942836d0830SLv Zheng 	mutex_lock(&acpi_debugger.lock);
943836d0830SLv Zheng 	module_put(owner);
944836d0830SLv Zheng err_lock:
945836d0830SLv Zheng 	mutex_unlock(&acpi_debugger.lock);
946836d0830SLv Zheng 	return ret;
947836d0830SLv Zheng }
948836d0830SLv Zheng 
acpi_debugger_read_cmd(char * buffer,size_t buffer_length)949836d0830SLv Zheng ssize_t acpi_debugger_read_cmd(char *buffer, size_t buffer_length)
950836d0830SLv Zheng {
951836d0830SLv Zheng 	ssize_t ret;
952836d0830SLv Zheng 	ssize_t (*func)(char *, size_t);
953836d0830SLv Zheng 	struct module *owner;
954836d0830SLv Zheng 
955836d0830SLv Zheng 	if (!acpi_debugger_initialized)
956836d0830SLv Zheng 		return -ENODEV;
957836d0830SLv Zheng 	mutex_lock(&acpi_debugger.lock);
958836d0830SLv Zheng 	if (!acpi_debugger.ops) {
959836d0830SLv Zheng 		ret = -ENODEV;
960836d0830SLv Zheng 		goto err_lock;
961836d0830SLv Zheng 	}
962836d0830SLv Zheng 	if (!try_module_get(acpi_debugger.owner)) {
963836d0830SLv Zheng 		ret = -ENODEV;
964836d0830SLv Zheng 		goto err_lock;
965836d0830SLv Zheng 	}
966836d0830SLv Zheng 	func = acpi_debugger.ops->read_cmd;
967836d0830SLv Zheng 	owner = acpi_debugger.owner;
968836d0830SLv Zheng 	mutex_unlock(&acpi_debugger.lock);
969836d0830SLv Zheng 
970836d0830SLv Zheng 	ret = func(buffer, buffer_length);
971836d0830SLv Zheng 
972836d0830SLv Zheng 	mutex_lock(&acpi_debugger.lock);
973836d0830SLv Zheng 	module_put(owner);
974836d0830SLv Zheng err_lock:
975836d0830SLv Zheng 	mutex_unlock(&acpi_debugger.lock);
976836d0830SLv Zheng 	return ret;
977836d0830SLv Zheng }
978836d0830SLv Zheng 
acpi_debugger_wait_command_ready(void)979836d0830SLv Zheng int acpi_debugger_wait_command_ready(void)
980836d0830SLv Zheng {
981836d0830SLv Zheng 	int ret;
982836d0830SLv Zheng 	int (*func)(bool, char *, size_t);
983836d0830SLv Zheng 	struct module *owner;
984836d0830SLv Zheng 
985836d0830SLv Zheng 	if (!acpi_debugger_initialized)
986836d0830SLv Zheng 		return -ENODEV;
987836d0830SLv Zheng 	mutex_lock(&acpi_debugger.lock);
988836d0830SLv Zheng 	if (!acpi_debugger.ops) {
989836d0830SLv Zheng 		ret = -ENODEV;
990836d0830SLv Zheng 		goto err_lock;
991836d0830SLv Zheng 	}
992836d0830SLv Zheng 	if (!try_module_get(acpi_debugger.owner)) {
993836d0830SLv Zheng 		ret = -ENODEV;
994836d0830SLv Zheng 		goto err_lock;
995836d0830SLv Zheng 	}
996836d0830SLv Zheng 	func = acpi_debugger.ops->wait_command_ready;
997836d0830SLv Zheng 	owner = acpi_debugger.owner;
998836d0830SLv Zheng 	mutex_unlock(&acpi_debugger.lock);
999836d0830SLv Zheng 
1000836d0830SLv Zheng 	ret = func(acpi_gbl_method_executing,
1001836d0830SLv Zheng 		   acpi_gbl_db_line_buf, ACPI_DB_LINE_BUFFER_SIZE);
1002836d0830SLv Zheng 
1003836d0830SLv Zheng 	mutex_lock(&acpi_debugger.lock);
1004836d0830SLv Zheng 	module_put(owner);
1005836d0830SLv Zheng err_lock:
1006836d0830SLv Zheng 	mutex_unlock(&acpi_debugger.lock);
1007836d0830SLv Zheng 	return ret;
1008836d0830SLv Zheng }
1009836d0830SLv Zheng 
acpi_debugger_notify_command_complete(void)1010836d0830SLv Zheng int acpi_debugger_notify_command_complete(void)
1011836d0830SLv Zheng {
1012836d0830SLv Zheng 	int ret;
1013836d0830SLv Zheng 	int (*func)(void);
1014836d0830SLv Zheng 	struct module *owner;
1015836d0830SLv Zheng 
1016836d0830SLv Zheng 	if (!acpi_debugger_initialized)
1017836d0830SLv Zheng 		return -ENODEV;
1018836d0830SLv Zheng 	mutex_lock(&acpi_debugger.lock);
1019836d0830SLv Zheng 	if (!acpi_debugger.ops) {
1020836d0830SLv Zheng 		ret = -ENODEV;
1021836d0830SLv Zheng 		goto err_lock;
1022836d0830SLv Zheng 	}
1023836d0830SLv Zheng 	if (!try_module_get(acpi_debugger.owner)) {
1024836d0830SLv Zheng 		ret = -ENODEV;
1025836d0830SLv Zheng 		goto err_lock;
1026836d0830SLv Zheng 	}
1027836d0830SLv Zheng 	func = acpi_debugger.ops->notify_command_complete;
1028836d0830SLv Zheng 	owner = acpi_debugger.owner;
1029836d0830SLv Zheng 	mutex_unlock(&acpi_debugger.lock);
1030836d0830SLv Zheng 
1031836d0830SLv Zheng 	ret = func();
1032836d0830SLv Zheng 
1033836d0830SLv Zheng 	mutex_lock(&acpi_debugger.lock);
1034836d0830SLv Zheng 	module_put(owner);
1035836d0830SLv Zheng err_lock:
1036836d0830SLv Zheng 	mutex_unlock(&acpi_debugger.lock);
1037836d0830SLv Zheng 	return ret;
1038836d0830SLv Zheng }
1039836d0830SLv Zheng 
acpi_debugger_init(void)1040836d0830SLv Zheng int __init acpi_debugger_init(void)
1041836d0830SLv Zheng {
1042836d0830SLv Zheng 	mutex_init(&acpi_debugger.lock);
1043836d0830SLv Zheng 	acpi_debugger_initialized = true;
1044836d0830SLv Zheng 	return 0;
1045836d0830SLv Zheng }
1046836d0830SLv Zheng #endif
1047836d0830SLv Zheng 
1048b8d35192SAlexey Starikovskiy /*******************************************************************************
1049b8d35192SAlexey Starikovskiy  *
1050b8d35192SAlexey Starikovskiy  * FUNCTION:    acpi_os_execute
1051b8d35192SAlexey Starikovskiy  *
1052b8d35192SAlexey Starikovskiy  * PARAMETERS:  Type               - Type of the callback
1053b8d35192SAlexey Starikovskiy  *              Function           - Function to be executed
1054b8d35192SAlexey Starikovskiy  *              Context            - Function parameters
1055b8d35192SAlexey Starikovskiy  *
1056b8d35192SAlexey Starikovskiy  * RETURN:      Status
1057b8d35192SAlexey Starikovskiy  *
1058b8d35192SAlexey Starikovskiy  * DESCRIPTION: Depending on type, either queues function for deferred execution or
1059b8d35192SAlexey Starikovskiy  *              immediately executes function on a separate thread.
1060b8d35192SAlexey Starikovskiy  *
1061b8d35192SAlexey Starikovskiy  ******************************************************************************/
1062b8d35192SAlexey Starikovskiy 
acpi_os_execute(acpi_execute_type type,acpi_osd_exec_callback function,void * context)10637b98118aSRafael J. Wysocki acpi_status acpi_os_execute(acpi_execute_type type,
10647b98118aSRafael J. Wysocki 			    acpi_osd_exec_callback function, void *context)
10651da177e4SLinus Torvalds {
10661da177e4SLinus Torvalds 	acpi_status status = AE_OK;
10671da177e4SLinus Torvalds 	struct acpi_os_dpc *dpc;
106817bc54eeSAlexey Starikovskiy 	struct workqueue_struct *queue;
106919cd847aSZhang Rui 	int ret;
107072945b2bSLen Brown 	ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
107172945b2bSLen Brown 			  "Scheduling function [%p(%p)] for deferred execution.\n",
107272945b2bSLen Brown 			  function, context));
10731da177e4SLinus Torvalds 
10748cfb0cdfSLv Zheng 	if (type == OSL_DEBUGGER_MAIN_THREAD) {
1075836d0830SLv Zheng 		ret = acpi_debugger_create_thread(function, context);
10768cfb0cdfSLv Zheng 		if (ret) {
10778aef273eSRafael J. Wysocki 			pr_err("Kernel thread creation failed\n");
10788cfb0cdfSLv Zheng 			status = AE_ERROR;
10798cfb0cdfSLv Zheng 		}
10808cfb0cdfSLv Zheng 		goto out_thread;
10818cfb0cdfSLv Zheng 	}
10828cfb0cdfSLv Zheng 
10831da177e4SLinus Torvalds 	/*
10841da177e4SLinus Torvalds 	 * Allocate/initialize DPC structure.  Note that this memory will be
108565f27f38SDavid Howells 	 * freed by the callee.  The kernel handles the work_struct list  in a
10861da177e4SLinus Torvalds 	 * way that allows us to also free its memory inside the callee.
10871da177e4SLinus Torvalds 	 * Because we may want to schedule several tasks with different
10881da177e4SLinus Torvalds 	 * parameters we can't use the approach some kernel code uses of
108965f27f38SDavid Howells 	 * having a static work_struct.
10901da177e4SLinus Torvalds 	 */
109172945b2bSLen Brown 
10923ae45a27SRafael J. Wysocki 	dpc = kzalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC);
10931da177e4SLinus Torvalds 	if (!dpc)
1094889c78beSLin Ming 		return AE_NO_MEMORY;
1095b976fe19SLinus Torvalds 
10961da177e4SLinus Torvalds 	dpc->function = function;
10971da177e4SLinus Torvalds 	dpc->context = context;
1098b976fe19SLinus Torvalds 
1099c02256beSZhang Rui 	/*
11003ae45a27SRafael J. Wysocki 	 * To prevent lockdep from complaining unnecessarily, make sure that
11013ae45a27SRafael J. Wysocki 	 * there is a different static lockdep key for each workqueue by using
11023ae45a27SRafael J. Wysocki 	 * INIT_WORK() for each of them separately.
1103c02256beSZhang Rui 	 */
11047b98118aSRafael J. Wysocki 	if (type == OSL_NOTIFY_HANDLER) {
11053ae45a27SRafael J. Wysocki 		queue = kacpi_notify_wq;
1106bc73675bSZhang Rui 		INIT_WORK(&dpc->work, acpi_os_execute_deferred);
11078cfb0cdfSLv Zheng 	} else if (type == OSL_GPE_HANDLER) {
11083ae45a27SRafael J. Wysocki 		queue = kacpid_wq;
1109bc73675bSZhang Rui 		INIT_WORK(&dpc->work, acpi_os_execute_deferred);
11108cfb0cdfSLv Zheng 	} else {
11118cfb0cdfSLv Zheng 		pr_err("Unsupported os_execute type %d.\n", type);
11128cfb0cdfSLv Zheng 		status = AE_ERROR;
11133ae45a27SRafael J. Wysocki 	}
1114bc73675bSZhang Rui 
11158cfb0cdfSLv Zheng 	if (ACPI_FAILURE(status))
11168cfb0cdfSLv Zheng 		goto err_workqueue;
11178cfb0cdfSLv Zheng 
11188fec62b2STejun Heo 	/*
11198fec62b2STejun Heo 	 * On some machines, a software-initiated SMI causes corruption unless
11208fec62b2STejun Heo 	 * the SMI runs on CPU 0.  An SMI can be initiated by any AML, but
11218fec62b2STejun Heo 	 * typically it's done in GPE-related methods that are run via
11228fec62b2STejun Heo 	 * workqueues, so we can avoid the known corruption cases by always
11238fec62b2STejun Heo 	 * queueing on CPU 0.
11248fec62b2STejun Heo 	 */
11258fec62b2STejun Heo 	ret = queue_work_on(0, queue, &dpc->work);
112619cd847aSZhang Rui 	if (!ret) {
11278aef273eSRafael J. Wysocki 		pr_err("Unable to queue work\n");
1128b976fe19SLinus Torvalds 		status = AE_ERROR;
1129b8d35192SAlexey Starikovskiy 	}
11308cfb0cdfSLv Zheng err_workqueue:
11318cfb0cdfSLv Zheng 	if (ACPI_FAILURE(status))
11328cfb0cdfSLv Zheng 		kfree(dpc);
11338cfb0cdfSLv Zheng out_thread:
1134889c78beSLin Ming 	return status;
11351da177e4SLinus Torvalds }
1136b8d35192SAlexey Starikovskiy EXPORT_SYMBOL(acpi_os_execute);
11371da177e4SLinus Torvalds 
acpi_os_wait_events_complete(void)1138bd6f10a5SLin Ming void acpi_os_wait_events_complete(void)
11391da177e4SLinus Torvalds {
114090253a79SLv Zheng 	/*
114190253a79SLv Zheng 	 * Make sure the GPE handler or the fixed event handler is not used
114290253a79SLv Zheng 	 * on another CPU after removal.
114390253a79SLv Zheng 	 */
1144efb1cf7dSChen Yu 	if (acpi_sci_irq_valid())
1145efb1cf7dSChen Yu 		synchronize_hardirq(acpi_sci_irq);
11461da177e4SLinus Torvalds 	flush_workqueue(kacpid_wq);
11472f67a069SZhang Rui 	flush_workqueue(kacpi_notify_wq);
11481da177e4SLinus Torvalds }
1149757c968cSRonald Tschalär EXPORT_SYMBOL(acpi_os_wait_events_complete);
11504be44fcdSLen Brown 
11517b98118aSRafael J. Wysocki struct acpi_hp_work {
11527b98118aSRafael J. Wysocki 	struct work_struct work;
11531e3bcb59SRafael J. Wysocki 	struct acpi_device *adev;
11547b98118aSRafael J. Wysocki 	u32 src;
11557b98118aSRafael J. Wysocki };
11567b98118aSRafael J. Wysocki 
acpi_hotplug_work_fn(struct work_struct * work)11577b98118aSRafael J. Wysocki static void acpi_hotplug_work_fn(struct work_struct *work)
11587b98118aSRafael J. Wysocki {
11597b98118aSRafael J. Wysocki 	struct acpi_hp_work *hpw = container_of(work, struct acpi_hp_work, work);
11607b98118aSRafael J. Wysocki 
11617b98118aSRafael J. Wysocki 	acpi_os_wait_events_complete();
11621e3bcb59SRafael J. Wysocki 	acpi_device_hotplug(hpw->adev, hpw->src);
11637b98118aSRafael J. Wysocki 	kfree(hpw);
11647b98118aSRafael J. Wysocki }
11657b98118aSRafael J. Wysocki 
acpi_hotplug_schedule(struct acpi_device * adev,u32 src)11661e3bcb59SRafael J. Wysocki acpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src)
11677b98118aSRafael J. Wysocki {
11687b98118aSRafael J. Wysocki 	struct acpi_hp_work *hpw;
11697b98118aSRafael J. Wysocki 
11708aef273eSRafael J. Wysocki 	acpi_handle_debug(adev->handle,
11718aef273eSRafael J. Wysocki 			  "Scheduling hotplug event %u for deferred handling\n",
11728aef273eSRafael J. Wysocki 			   src);
11737b98118aSRafael J. Wysocki 
11747b98118aSRafael J. Wysocki 	hpw = kmalloc(sizeof(*hpw), GFP_KERNEL);
11757b98118aSRafael J. Wysocki 	if (!hpw)
11767b98118aSRafael J. Wysocki 		return AE_NO_MEMORY;
11777b98118aSRafael J. Wysocki 
11787b98118aSRafael J. Wysocki 	INIT_WORK(&hpw->work, acpi_hotplug_work_fn);
11791e3bcb59SRafael J. Wysocki 	hpw->adev = adev;
11807b98118aSRafael J. Wysocki 	hpw->src = src;
11817b98118aSRafael J. Wysocki 	/*
11827b98118aSRafael J. Wysocki 	 * We can't run hotplug code in kacpid_wq/kacpid_notify_wq etc., because
11837b98118aSRafael J. Wysocki 	 * the hotplug code may call driver .remove() functions, which may
11847b98118aSRafael J. Wysocki 	 * invoke flush_scheduled_work()/acpi_os_wait_events_complete() to flush
11857b98118aSRafael J. Wysocki 	 * these workqueues.
11867b98118aSRafael J. Wysocki 	 */
11877b98118aSRafael J. Wysocki 	if (!queue_work(kacpi_hotplug_wq, &hpw->work)) {
11887b98118aSRafael J. Wysocki 		kfree(hpw);
11897b98118aSRafael J. Wysocki 		return AE_ERROR;
11907b98118aSRafael J. Wysocki 	}
11917b98118aSRafael J. Wysocki 	return AE_OK;
11927b98118aSRafael J. Wysocki }
11937b98118aSRafael J. Wysocki 
acpi_queue_hotplug_work(struct work_struct * work)1194d783156eSRafael J. Wysocki bool acpi_queue_hotplug_work(struct work_struct *work)
1195d783156eSRafael J. Wysocki {
1196d783156eSRafael J. Wysocki 	return queue_work(kacpi_hotplug_wq, work);
1197d783156eSRafael J. Wysocki }
11981da177e4SLinus Torvalds 
11991da177e4SLinus Torvalds acpi_status
acpi_os_create_semaphore(u32 max_units,u32 initial_units,acpi_handle * handle)12004be44fcdSLen Brown acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle)
12011da177e4SLinus Torvalds {
12021da177e4SLinus Torvalds 	struct semaphore *sem = NULL;
12031da177e4SLinus Torvalds 
12042d0acb4aSjhbird.choi@samsung.com 	sem = acpi_os_allocate_zeroed(sizeof(struct semaphore));
12051da177e4SLinus Torvalds 	if (!sem)
1206d550d98dSPatrick Mochel 		return AE_NO_MEMORY;
12071da177e4SLinus Torvalds 
12081da177e4SLinus Torvalds 	sema_init(sem, initial_units);
12091da177e4SLinus Torvalds 
12101da177e4SLinus Torvalds 	*handle = (acpi_handle *) sem;
12111da177e4SLinus Torvalds 
12124be44fcdSLen Brown 	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Creating semaphore[%p|%d].\n",
12134be44fcdSLen Brown 			  *handle, initial_units));
12141da177e4SLinus Torvalds 
1215d550d98dSPatrick Mochel 	return AE_OK;
12161da177e4SLinus Torvalds }
12171da177e4SLinus Torvalds 
12181da177e4SLinus Torvalds /*
12191da177e4SLinus Torvalds  * TODO: A better way to delete semaphores?  Linux doesn't have a
12201da177e4SLinus Torvalds  * 'delete_semaphore()' function -- may result in an invalid
12211da177e4SLinus Torvalds  * pointer dereference for non-synchronized consumers.	Should
12221da177e4SLinus Torvalds  * we at least check for blocked threads and signal/cancel them?
12231da177e4SLinus Torvalds  */
12241da177e4SLinus Torvalds 
acpi_os_delete_semaphore(acpi_handle handle)12254be44fcdSLen Brown acpi_status acpi_os_delete_semaphore(acpi_handle handle)
12261da177e4SLinus Torvalds {
12271da177e4SLinus Torvalds 	struct semaphore *sem = (struct semaphore *)handle;
12281da177e4SLinus Torvalds 
12291da177e4SLinus Torvalds 	if (!sem)
1230d550d98dSPatrick Mochel 		return AE_BAD_PARAMETER;
12311da177e4SLinus Torvalds 
12321da177e4SLinus Torvalds 	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Deleting semaphore[%p].\n", handle));
12331da177e4SLinus Torvalds 
1234f1241c87SMatthew Wilcox 	BUG_ON(!list_empty(&sem->wait_list));
123502438d87SLen Brown 	kfree(sem);
12364be44fcdSLen Brown 	sem = NULL;
12371da177e4SLinus Torvalds 
1238d550d98dSPatrick Mochel 	return AE_OK;
12391da177e4SLinus Torvalds }
12401da177e4SLinus Torvalds 
12411da177e4SLinus Torvalds /*
12421da177e4SLinus Torvalds  * TODO: Support for units > 1?
12431da177e4SLinus Torvalds  */
acpi_os_wait_semaphore(acpi_handle handle,u32 units,u16 timeout)12444be44fcdSLen Brown acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout)
12451da177e4SLinus Torvalds {
12461da177e4SLinus Torvalds 	acpi_status status = AE_OK;
12471da177e4SLinus Torvalds 	struct semaphore *sem = (struct semaphore *)handle;
1248f1241c87SMatthew Wilcox 	long jiffies;
12491da177e4SLinus Torvalds 	int ret = 0;
12501da177e4SLinus Torvalds 
12517901a052SLv Zheng 	if (!acpi_os_initialized)
12527901a052SLv Zheng 		return AE_OK;
12537901a052SLv Zheng 
12541da177e4SLinus Torvalds 	if (!sem || (units < 1))
1255d550d98dSPatrick Mochel 		return AE_BAD_PARAMETER;
12561da177e4SLinus Torvalds 
12571da177e4SLinus Torvalds 	if (units > 1)
1258d550d98dSPatrick Mochel 		return AE_SUPPORT;
12591da177e4SLinus Torvalds 
12604be44fcdSLen Brown 	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Waiting for semaphore[%p|%d|%d]\n",
12614be44fcdSLen Brown 			  handle, units, timeout));
12621da177e4SLinus Torvalds 
1263f1241c87SMatthew Wilcox 	if (timeout == ACPI_WAIT_FOREVER)
1264f1241c87SMatthew Wilcox 		jiffies = MAX_SCHEDULE_TIMEOUT;
1265f1241c87SMatthew Wilcox 	else
1266f1241c87SMatthew Wilcox 		jiffies = msecs_to_jiffies(timeout);
1267d68909f4SLen Brown 
1268f1241c87SMatthew Wilcox 	ret = down_timeout(sem, jiffies);
1269f1241c87SMatthew Wilcox 	if (ret)
12701da177e4SLinus Torvalds 		status = AE_TIME;
12711da177e4SLinus Torvalds 
12721da177e4SLinus Torvalds 	if (ACPI_FAILURE(status)) {
12739e7e2c04SBjorn Helgaas 		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
1274a6fc6720SThomas Renninger 				  "Failed to acquire semaphore[%p|%d|%d], %s",
12754be44fcdSLen Brown 				  handle, units, timeout,
12764be44fcdSLen Brown 				  acpi_format_exception(status)));
12774be44fcdSLen Brown 	} else {
12784be44fcdSLen Brown 		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
1279a6fc6720SThomas Renninger 				  "Acquired semaphore[%p|%d|%d]", handle,
12804be44fcdSLen Brown 				  units, timeout));
12811da177e4SLinus Torvalds 	}
12821da177e4SLinus Torvalds 
1283d550d98dSPatrick Mochel 	return status;
12841da177e4SLinus Torvalds }
12851da177e4SLinus Torvalds 
12861da177e4SLinus Torvalds /*
12871da177e4SLinus Torvalds  * TODO: Support for units > 1?
12881da177e4SLinus Torvalds  */
acpi_os_signal_semaphore(acpi_handle handle,u32 units)12894be44fcdSLen Brown acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units)
12901da177e4SLinus Torvalds {
12911da177e4SLinus Torvalds 	struct semaphore *sem = (struct semaphore *)handle;
12921da177e4SLinus Torvalds 
12937901a052SLv Zheng 	if (!acpi_os_initialized)
12947901a052SLv Zheng 		return AE_OK;
12957901a052SLv Zheng 
12961da177e4SLinus Torvalds 	if (!sem || (units < 1))
1297d550d98dSPatrick Mochel 		return AE_BAD_PARAMETER;
12981da177e4SLinus Torvalds 
12991da177e4SLinus Torvalds 	if (units > 1)
1300d550d98dSPatrick Mochel 		return AE_SUPPORT;
13011da177e4SLinus Torvalds 
13024be44fcdSLen Brown 	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Signaling semaphore[%p|%d]\n", handle,
13034be44fcdSLen Brown 			  units));
13041da177e4SLinus Torvalds 
13051da177e4SLinus Torvalds 	up(sem);
13061da177e4SLinus Torvalds 
1307d550d98dSPatrick Mochel 	return AE_OK;
13081da177e4SLinus Torvalds }
13094be44fcdSLen Brown 
acpi_os_get_line(char * buffer,u32 buffer_length,u32 * bytes_read)13104d946f79SLv Zheng acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read)
13111da177e4SLinus Torvalds {
13121da177e4SLinus Torvalds #ifdef ENABLE_DEBUGGER
13131da177e4SLinus Torvalds 	if (acpi_in_debugger) {
13141da177e4SLinus Torvalds 		u32 chars;
13151da177e4SLinus Torvalds 
13164d946f79SLv Zheng 		kdb_read(buffer, buffer_length);
13171da177e4SLinus Torvalds 
13181da177e4SLinus Torvalds 		/* remove the CR kdb includes */
13191da177e4SLinus Torvalds 		chars = strlen(buffer) - 1;
13201da177e4SLinus Torvalds 		buffer[chars] = '\0';
13211da177e4SLinus Torvalds 	}
13228cfb0cdfSLv Zheng #else
13238cfb0cdfSLv Zheng 	int ret;
13248cfb0cdfSLv Zheng 
1325836d0830SLv Zheng 	ret = acpi_debugger_read_cmd(buffer, buffer_length);
13268cfb0cdfSLv Zheng 	if (ret < 0)
13278cfb0cdfSLv Zheng 		return AE_ERROR;
13288cfb0cdfSLv Zheng 	if (bytes_read)
13298cfb0cdfSLv Zheng 		*bytes_read = ret;
13301da177e4SLinus Torvalds #endif
13311da177e4SLinus Torvalds 
13324d946f79SLv Zheng 	return AE_OK;
13331da177e4SLinus Torvalds }
1334836d0830SLv Zheng EXPORT_SYMBOL(acpi_os_get_line);
13351da177e4SLinus Torvalds 
acpi_os_wait_command_ready(void)13368cfb0cdfSLv Zheng acpi_status acpi_os_wait_command_ready(void)
13378cfb0cdfSLv Zheng {
13388cfb0cdfSLv Zheng 	int ret;
13398cfb0cdfSLv Zheng 
1340836d0830SLv Zheng 	ret = acpi_debugger_wait_command_ready();
13418cfb0cdfSLv Zheng 	if (ret < 0)
13428cfb0cdfSLv Zheng 		return AE_ERROR;
13438cfb0cdfSLv Zheng 	return AE_OK;
13448cfb0cdfSLv Zheng }
13458cfb0cdfSLv Zheng 
acpi_os_notify_command_complete(void)13468cfb0cdfSLv Zheng acpi_status acpi_os_notify_command_complete(void)
13478cfb0cdfSLv Zheng {
13488cfb0cdfSLv Zheng 	int ret;
13498cfb0cdfSLv Zheng 
1350836d0830SLv Zheng 	ret = acpi_debugger_notify_command_complete();
13518cfb0cdfSLv Zheng 	if (ret < 0)
13528cfb0cdfSLv Zheng 		return AE_ERROR;
13538cfb0cdfSLv Zheng 	return AE_OK;
13548cfb0cdfSLv Zheng }
13558cfb0cdfSLv Zheng 
acpi_os_signal(u32 function,void * info)13564be44fcdSLen Brown acpi_status acpi_os_signal(u32 function, void *info)
13571da177e4SLinus Torvalds {
13584be44fcdSLen Brown 	switch (function) {
13591da177e4SLinus Torvalds 	case ACPI_SIGNAL_FATAL:
13608aef273eSRafael J. Wysocki 		pr_err("Fatal opcode executed\n");
13611da177e4SLinus Torvalds 		break;
13621da177e4SLinus Torvalds 	case ACPI_SIGNAL_BREAKPOINT:
13631da177e4SLinus Torvalds 		/*
13641da177e4SLinus Torvalds 		 * AML Breakpoint
13651da177e4SLinus Torvalds 		 * ACPI spec. says to treat it as a NOP unless
13661da177e4SLinus Torvalds 		 * you are debugging.  So if/when we integrate
13671da177e4SLinus Torvalds 		 * AML debugger into the kernel debugger its
13681da177e4SLinus Torvalds 		 * hook will go here.  But until then it is
13691da177e4SLinus Torvalds 		 * not useful to print anything on breakpoints.
13701da177e4SLinus Torvalds 		 */
13711da177e4SLinus Torvalds 		break;
13721da177e4SLinus Torvalds 	default:
13731da177e4SLinus Torvalds 		break;
13741da177e4SLinus Torvalds 	}
13751da177e4SLinus Torvalds 
13761da177e4SLinus Torvalds 	return AE_OK;
13771da177e4SLinus Torvalds }
13784be44fcdSLen Brown 
acpi_os_name_setup(char * str)13794be44fcdSLen Brown static int __init acpi_os_name_setup(char *str)
13801da177e4SLinus Torvalds {
13811da177e4SLinus Torvalds 	char *p = acpi_os_name;
13821da177e4SLinus Torvalds 	int count = ACPI_MAX_OVERRIDE_LEN - 1;
13831da177e4SLinus Torvalds 
13841da177e4SLinus Torvalds 	if (!str || !*str)
13851da177e4SLinus Torvalds 		return 0;
13861da177e4SLinus Torvalds 
13875e2be4e0SDan Carpenter 	for (; count-- && *str; str++) {
13881da177e4SLinus Torvalds 		if (isalnum(*str) || *str == ' ' || *str == ':')
13891da177e4SLinus Torvalds 			*p++ = *str;
13901da177e4SLinus Torvalds 		else if (*str == '\'' || *str == '"')
13911da177e4SLinus Torvalds 			continue;
13921da177e4SLinus Torvalds 		else
13931da177e4SLinus Torvalds 			break;
13941da177e4SLinus Torvalds 	}
13951da177e4SLinus Torvalds 	*p = 0;
13961da177e4SLinus Torvalds 
13971da177e4SLinus Torvalds 	return 1;
13981da177e4SLinus Torvalds 
13991da177e4SLinus Torvalds }
14001da177e4SLinus Torvalds 
14011da177e4SLinus Torvalds __setup("acpi_os_name=", acpi_os_name_setup);
14021da177e4SLinus Torvalds 
140322b5afceSBob Moore /*
140408e1d7c0SLv Zheng  * Disable the auto-serialization of named objects creation methods.
140522b5afceSBob Moore  *
140608e1d7c0SLv Zheng  * This feature is enabled by default.  It marks the AML control methods
140722b5afceSBob Moore  * that contain the opcodes to create named objects as "Serialized".
140822b5afceSBob Moore  */
acpi_no_auto_serialize_setup(char * str)140908e1d7c0SLv Zheng static int __init acpi_no_auto_serialize_setup(char *str)
14101da177e4SLinus Torvalds {
141108e1d7c0SLv Zheng 	acpi_gbl_auto_serialize_methods = FALSE;
14128aef273eSRafael J. Wysocki 	pr_info("Auto-serialization disabled\n");
14131da177e4SLinus Torvalds 
14141da177e4SLinus Torvalds 	return 1;
14151da177e4SLinus Torvalds }
14161da177e4SLinus Torvalds 
141708e1d7c0SLv Zheng __setup("acpi_no_auto_serialize", acpi_no_auto_serialize_setup);
14181da177e4SLinus Torvalds 
1419df92e695SThomas Renninger /* Check of resource interference between native drivers and ACPI
1420df92e695SThomas Renninger  * OperationRegions (SystemIO and System Memory only).
1421df92e695SThomas Renninger  * IO ports and memory declared in ACPI might be used by the ACPI subsystem
1422df92e695SThomas Renninger  * in arbitrary AML code and can interfere with legacy drivers.
1423df92e695SThomas Renninger  * acpi_enforce_resources= can be set to:
1424df92e695SThomas Renninger  *
14257e90560cSLuca Tettamanti  *   - strict (default) (2)
1426df92e695SThomas Renninger  *     -> further driver trying to access the resources will not load
14277e90560cSLuca Tettamanti  *   - lax              (1)
1428df92e695SThomas Renninger  *     -> further driver trying to access the resources will load, but you
1429df92e695SThomas Renninger  *     get a system message that something might go wrong...
1430df92e695SThomas Renninger  *
1431df92e695SThomas Renninger  *   - no               (0)
1432df92e695SThomas Renninger  *     -> ACPI Operation Region resources will not be registered
1433df92e695SThomas Renninger  *
1434df92e695SThomas Renninger  */
1435df92e695SThomas Renninger #define ENFORCE_RESOURCES_STRICT 2
1436df92e695SThomas Renninger #define ENFORCE_RESOURCES_LAX    1
1437df92e695SThomas Renninger #define ENFORCE_RESOURCES_NO     0
1438df92e695SThomas Renninger 
14397e90560cSLuca Tettamanti static unsigned int acpi_enforce_resources = ENFORCE_RESOURCES_STRICT;
1440df92e695SThomas Renninger 
acpi_enforce_resources_setup(char * str)1441df92e695SThomas Renninger static int __init acpi_enforce_resources_setup(char *str)
1442df92e695SThomas Renninger {
1443df92e695SThomas Renninger 	if (str == NULL || *str == '\0')
1444df92e695SThomas Renninger 		return 0;
1445df92e695SThomas Renninger 
1446df92e695SThomas Renninger 	if (!strcmp("strict", str))
1447df92e695SThomas Renninger 		acpi_enforce_resources = ENFORCE_RESOURCES_STRICT;
1448df92e695SThomas Renninger 	else if (!strcmp("lax", str))
1449df92e695SThomas Renninger 		acpi_enforce_resources = ENFORCE_RESOURCES_LAX;
1450df92e695SThomas Renninger 	else if (!strcmp("no", str))
1451df92e695SThomas Renninger 		acpi_enforce_resources = ENFORCE_RESOURCES_NO;
1452df92e695SThomas Renninger 
1453df92e695SThomas Renninger 	return 1;
1454df92e695SThomas Renninger }
1455df92e695SThomas Renninger 
1456df92e695SThomas Renninger __setup("acpi_enforce_resources=", acpi_enforce_resources_setup);
1457df92e695SThomas Renninger 
1458df92e695SThomas Renninger /* Check for resource conflicts between ACPI OperationRegions and native
1459df92e695SThomas Renninger  * drivers */
acpi_check_resource_conflict(const struct resource * res)1460876fba43SJean Delvare int acpi_check_resource_conflict(const struct resource *res)
1461df92e695SThomas Renninger {
1462f654c0feSLin Ming 	acpi_adr_space_type space_id;
1463df92e695SThomas Renninger 
1464df92e695SThomas Renninger 	if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
1465df92e695SThomas Renninger 		return 0;
1466df92e695SThomas Renninger 
1467f654c0feSLin Ming 	if (res->flags & IORESOURCE_IO)
1468f654c0feSLin Ming 		space_id = ACPI_ADR_SPACE_SYSTEM_IO;
1469505ca2f7SRafael J. Wysocki 	else if (res->flags & IORESOURCE_MEM)
1470f654c0feSLin Ming 		space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY;
1471505ca2f7SRafael J. Wysocki 	else
1472505ca2f7SRafael J. Wysocki 		return 0;
1473df92e695SThomas Renninger 
1474505ca2f7SRafael J. Wysocki 	if (!acpi_check_address_range(space_id, res->start, resource_size(res), 1))
1475505ca2f7SRafael J. Wysocki 		return 0;
1476df92e695SThomas Renninger 
1477505ca2f7SRafael J. Wysocki 	pr_info("Resource conflict; ACPI support missing from driver?\n");
1478505ca2f7SRafael J. Wysocki 
1479df92e695SThomas Renninger 	if (acpi_enforce_resources == ENFORCE_RESOURCES_STRICT)
1480df92e695SThomas Renninger 		return -EBUSY;
1481505ca2f7SRafael J. Wysocki 
1482505ca2f7SRafael J. Wysocki 	if (acpi_enforce_resources == ENFORCE_RESOURCES_LAX)
1483505ca2f7SRafael J. Wysocki 		pr_notice("Resource conflict: System may be unstable or behave erratically\n");
1484505ca2f7SRafael J. Wysocki 
1485df92e695SThomas Renninger 	return 0;
1486df92e695SThomas Renninger }
1487443dea72SThomas Renninger EXPORT_SYMBOL(acpi_check_resource_conflict);
1488df92e695SThomas Renninger 
acpi_check_region(resource_size_t start,resource_size_t n,const char * name)1489df92e695SThomas Renninger int acpi_check_region(resource_size_t start, resource_size_t n,
1490df92e695SThomas Renninger 		      const char *name)
1491df92e695SThomas Renninger {
149201c3d593SZhen Lei 	struct resource res = DEFINE_RES_IO_NAMED(start, n, name);
1493df92e695SThomas Renninger 
1494df92e695SThomas Renninger 	return acpi_check_resource_conflict(&res);
1495df92e695SThomas Renninger }
1496df92e695SThomas Renninger EXPORT_SYMBOL(acpi_check_region);
1497df92e695SThomas Renninger 
14981da177e4SLinus Torvalds /*
149970dd6beaSJean Delvare  * Let drivers know whether the resource checks are effective
150070dd6beaSJean Delvare  */
acpi_resources_are_enforced(void)150170dd6beaSJean Delvare int acpi_resources_are_enforced(void)
150270dd6beaSJean Delvare {
150370dd6beaSJean Delvare 	return acpi_enforce_resources == ENFORCE_RESOURCES_STRICT;
150470dd6beaSJean Delvare }
150570dd6beaSJean Delvare EXPORT_SYMBOL(acpi_resources_are_enforced);
150670dd6beaSJean Delvare 
150770dd6beaSJean Delvare /*
15089f63b88bSLin Ming  * Deallocate the memory for a spinlock.
15099f63b88bSLin Ming  */
acpi_os_delete_lock(acpi_spinlock handle)15109f63b88bSLin Ming void acpi_os_delete_lock(acpi_spinlock handle)
15119f63b88bSLin Ming {
15129f63b88bSLin Ming 	ACPI_FREE(handle);
15139f63b88bSLin Ming }
15149f63b88bSLin Ming 
15159f63b88bSLin Ming /*
151673459f73SRobert Moore  * Acquire a spinlock.
151773459f73SRobert Moore  *
151873459f73SRobert Moore  * handle is a pointer to the spinlock_t.
151973459f73SRobert Moore  */
152073459f73SRobert Moore 
acpi_os_acquire_lock(acpi_spinlock lockp)1521967440e3SBob Moore acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp)
15222288eba5SJules Irenge 	__acquires(lockp)
152373459f73SRobert Moore {
1524b8e4d893SBob Moore 	acpi_cpu_flags flags;
1525967440e3SBob Moore 	spin_lock_irqsave(lockp, flags);
152673459f73SRobert Moore 	return flags;
152773459f73SRobert Moore }
152873459f73SRobert Moore 
152973459f73SRobert Moore /*
153073459f73SRobert Moore  * Release a spinlock. See above.
153173459f73SRobert Moore  */
153273459f73SRobert Moore 
acpi_os_release_lock(acpi_spinlock lockp,acpi_cpu_flags flags)1533967440e3SBob Moore void acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags flags)
15342288eba5SJules Irenge 	__releases(lockp)
153573459f73SRobert Moore {
1536967440e3SBob Moore 	spin_unlock_irqrestore(lockp, flags);
153773459f73SRobert Moore }
153873459f73SRobert Moore 
153973459f73SRobert Moore #ifndef ACPI_USE_LOCAL_CACHE
154073459f73SRobert Moore 
154173459f73SRobert Moore /*******************************************************************************
154273459f73SRobert Moore  *
154373459f73SRobert Moore  * FUNCTION:    acpi_os_create_cache
154473459f73SRobert Moore  *
1545b229cf92SBob Moore  * PARAMETERS:  name      - Ascii name for the cache
1546b229cf92SBob Moore  *              size      - Size of each cached object
1547b229cf92SBob Moore  *              depth     - Maximum depth of the cache (in objects) <ignored>
1548b229cf92SBob Moore  *              cache     - Where the new cache object is returned
154973459f73SRobert Moore  *
1550b229cf92SBob Moore  * RETURN:      status
155173459f73SRobert Moore  *
155273459f73SRobert Moore  * DESCRIPTION: Create a cache object
155373459f73SRobert Moore  *
155473459f73SRobert Moore  ******************************************************************************/
155573459f73SRobert Moore 
155673459f73SRobert Moore acpi_status
acpi_os_create_cache(char * name,u16 size,u16 depth,acpi_cache_t ** cache)15574be44fcdSLen Brown acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache)
155873459f73SRobert Moore {
155920c2df83SPaul Mundt 	*cache = kmem_cache_create(name, size, 0, 0, NULL);
1560a6fdbf90SAdrian Bunk 	if (*cache == NULL)
1561b229cf92SBob Moore 		return AE_ERROR;
1562b229cf92SBob Moore 	else
156373459f73SRobert Moore 		return AE_OK;
156473459f73SRobert Moore }
156573459f73SRobert Moore 
156673459f73SRobert Moore /*******************************************************************************
156773459f73SRobert Moore  *
156873459f73SRobert Moore  * FUNCTION:    acpi_os_purge_cache
156973459f73SRobert Moore  *
157073459f73SRobert Moore  * PARAMETERS:  Cache           - Handle to cache object
157173459f73SRobert Moore  *
157273459f73SRobert Moore  * RETURN:      Status
157373459f73SRobert Moore  *
157473459f73SRobert Moore  * DESCRIPTION: Free all objects within the requested cache.
157573459f73SRobert Moore  *
157673459f73SRobert Moore  ******************************************************************************/
157773459f73SRobert Moore 
acpi_os_purge_cache(acpi_cache_t * cache)15784be44fcdSLen Brown acpi_status acpi_os_purge_cache(acpi_cache_t * cache)
157973459f73SRobert Moore {
158050dd0969SJan Engelhardt 	kmem_cache_shrink(cache);
158173459f73SRobert Moore 	return (AE_OK);
158273459f73SRobert Moore }
158373459f73SRobert Moore 
158473459f73SRobert Moore /*******************************************************************************
158573459f73SRobert Moore  *
158673459f73SRobert Moore  * FUNCTION:    acpi_os_delete_cache
158773459f73SRobert Moore  *
158873459f73SRobert Moore  * PARAMETERS:  Cache           - Handle to cache object
158973459f73SRobert Moore  *
159073459f73SRobert Moore  * RETURN:      Status
159173459f73SRobert Moore  *
159273459f73SRobert Moore  * DESCRIPTION: Free all objects within the requested cache and delete the
159373459f73SRobert Moore  *              cache object.
159473459f73SRobert Moore  *
159573459f73SRobert Moore  ******************************************************************************/
159673459f73SRobert Moore 
acpi_os_delete_cache(acpi_cache_t * cache)15974be44fcdSLen Brown acpi_status acpi_os_delete_cache(acpi_cache_t * cache)
159873459f73SRobert Moore {
15991a1d92c1SAlexey Dobriyan 	kmem_cache_destroy(cache);
160073459f73SRobert Moore 	return (AE_OK);
160173459f73SRobert Moore }
160273459f73SRobert Moore 
160373459f73SRobert Moore /*******************************************************************************
160473459f73SRobert Moore  *
160573459f73SRobert Moore  * FUNCTION:    acpi_os_release_object
160673459f73SRobert Moore  *
160773459f73SRobert Moore  * PARAMETERS:  Cache       - Handle to cache object
160873459f73SRobert Moore  *              Object      - The object to be released
160973459f73SRobert Moore  *
161073459f73SRobert Moore  * RETURN:      None
161173459f73SRobert Moore  *
161273459f73SRobert Moore  * DESCRIPTION: Release an object to the specified cache.  If cache is full,
161373459f73SRobert Moore  *              the object is deleted.
161473459f73SRobert Moore  *
161573459f73SRobert Moore  ******************************************************************************/
161673459f73SRobert Moore 
acpi_os_release_object(acpi_cache_t * cache,void * object)16174be44fcdSLen Brown acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
161873459f73SRobert Moore {
161973459f73SRobert Moore 	kmem_cache_free(cache, object);
162073459f73SRobert Moore 	return (AE_OK);
162173459f73SRobert Moore }
162273459f73SRobert Moore #endif
1623d362edafSMyron Stowe 
acpi_no_static_ssdt_setup(char * s)1624a94e88cdSLv Zheng static int __init acpi_no_static_ssdt_setup(char *s)
1625b75dd297SLv Zheng {
1626a94e88cdSLv Zheng 	acpi_gbl_disable_ssdt_table_install = TRUE;
16278aef273eSRafael J. Wysocki 	pr_info("Static SSDT installation disabled\n");
1628b75dd297SLv Zheng 
1629a94e88cdSLv Zheng 	return 0;
1630b75dd297SLv Zheng }
1631b75dd297SLv Zheng 
1632a94e88cdSLv Zheng early_param("acpi_no_static_ssdt", acpi_no_static_ssdt_setup);
1633b75dd297SLv Zheng 
acpi_disable_return_repair(char * s)16344dde507fSLv Zheng static int __init acpi_disable_return_repair(char *s)
16354dde507fSLv Zheng {
16368aef273eSRafael J. Wysocki 	pr_notice("Predefined validation mechanism disabled\n");
16374dde507fSLv Zheng 	acpi_gbl_disable_auto_repair = TRUE;
16384dde507fSLv Zheng 
16394dde507fSLv Zheng 	return 1;
16404dde507fSLv Zheng }
16414dde507fSLv Zheng 
16424dde507fSLv Zheng __setup("acpica_no_return_repair", acpi_disable_return_repair);
16434dde507fSLv Zheng 
acpi_os_initialize(void)1644d362edafSMyron Stowe acpi_status __init acpi_os_initialize(void)
1645d362edafSMyron Stowe {
1646d362edafSMyron Stowe 	acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1a_event_block);
1647d362edafSMyron Stowe 	acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1b_event_block);
164885f94020SRafael J. Wysocki 
164985f94020SRafael J. Wysocki 	acpi_gbl_xgpe0_block_logical_address =
165085f94020SRafael J. Wysocki 		(unsigned long)acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe0_block);
165185f94020SRafael J. Wysocki 	acpi_gbl_xgpe1_block_logical_address =
165285f94020SRafael J. Wysocki 		(unsigned long)acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe1_block);
165385f94020SRafael J. Wysocki 
1654a4714a89SRandy Wright 	if (acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) {
1655a4714a89SRandy Wright 		/*
1656a4714a89SRandy Wright 		 * Use acpi_os_map_generic_address to pre-map the reset
1657a4714a89SRandy Wright 		 * register if it's in system memory.
1658a4714a89SRandy Wright 		 */
16596915564dSRafael J. Wysocki 		void *rv;
1660a4714a89SRandy Wright 
1661a4714a89SRandy Wright 		rv = acpi_os_map_generic_address(&acpi_gbl_FADT.reset_register);
16628aef273eSRafael J. Wysocki 		pr_debug("%s: Reset register mapping %s\n", __func__,
16636915564dSRafael J. Wysocki 			 rv ? "successful" : "failed");
1664a4714a89SRandy Wright 	}
16657901a052SLv Zheng 	acpi_os_initialized = true;
1666d362edafSMyron Stowe 
1667d362edafSMyron Stowe 	return AE_OK;
1668d362edafSMyron Stowe }
1669d362edafSMyron Stowe 
acpi_os_initialize1(void)167032d47eefSZhang Rui acpi_status __init acpi_os_initialize1(void)
1671d362edafSMyron Stowe {
167244d2588eSTejun Heo 	kacpid_wq = alloc_workqueue("kacpid", 0, 1);
167344d2588eSTejun Heo 	kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1);
1674d783156eSRafael J. Wysocki 	kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0);
1675d362edafSMyron Stowe 	BUG_ON(!kacpid_wq);
1676d362edafSMyron Stowe 	BUG_ON(!kacpi_notify_wq);
1677d362edafSMyron Stowe 	BUG_ON(!kacpi_hotplug_wq);
1678e5f660ebSLv Zheng 	acpi_osi_init();
1679d362edafSMyron Stowe 	return AE_OK;
1680d362edafSMyron Stowe }
1681d362edafSMyron Stowe 
acpi_os_terminate(void)1682d362edafSMyron Stowe acpi_status acpi_os_terminate(void)
1683d362edafSMyron Stowe {
1684d362edafSMyron Stowe 	if (acpi_irq_handler) {
168523fe3630SRafael J. Wysocki 		acpi_os_remove_interrupt_handler(acpi_gbl_FADT.sci_interrupt,
1686d362edafSMyron Stowe 						 acpi_irq_handler);
1687d362edafSMyron Stowe 	}
1688d362edafSMyron Stowe 
1689d362edafSMyron Stowe 	acpi_os_unmap_generic_address(&acpi_gbl_FADT.xgpe1_block);
1690d362edafSMyron Stowe 	acpi_os_unmap_generic_address(&acpi_gbl_FADT.xgpe0_block);
169185f94020SRafael J. Wysocki 	acpi_gbl_xgpe0_block_logical_address = 0UL;
169285f94020SRafael J. Wysocki 	acpi_gbl_xgpe1_block_logical_address = 0UL;
169385f94020SRafael J. Wysocki 
1694d362edafSMyron Stowe 	acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1b_event_block);
1695d362edafSMyron Stowe 	acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1a_event_block);
169685f94020SRafael J. Wysocki 
1697a4714a89SRandy Wright 	if (acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER)
1698a4714a89SRandy Wright 		acpi_os_unmap_generic_address(&acpi_gbl_FADT.reset_register);
1699d362edafSMyron Stowe 
1700d362edafSMyron Stowe 	destroy_workqueue(kacpid_wq);
1701d362edafSMyron Stowe 	destroy_workqueue(kacpi_notify_wq);
1702d362edafSMyron Stowe 	destroy_workqueue(kacpi_hotplug_wq);
1703d362edafSMyron Stowe 
1704d362edafSMyron Stowe 	return AE_OK;
1705d362edafSMyron Stowe }
170609f98a82STang Liang 
acpi_os_prepare_sleep(u8 sleep_state,u32 pm1a_control,u32 pm1b_control)170709f98a82STang Liang acpi_status acpi_os_prepare_sleep(u8 sleep_state, u32 pm1a_control,
170809f98a82STang Liang 				  u32 pm1b_control)
170909f98a82STang Liang {
171009f98a82STang Liang 	int rc = 0;
171109f98a82STang Liang 	if (__acpi_os_prepare_sleep)
171209f98a82STang Liang 		rc = __acpi_os_prepare_sleep(sleep_state,
171309f98a82STang Liang 					     pm1a_control, pm1b_control);
171409f98a82STang Liang 	if (rc < 0)
171509f98a82STang Liang 		return AE_ERROR;
171609f98a82STang Liang 	else if (rc > 0)
17170fc5e8f4SLv Zheng 		return AE_CTRL_TERMINATE;
171809f98a82STang Liang 
171909f98a82STang Liang 	return AE_OK;
172009f98a82STang Liang }
172109f98a82STang Liang 
acpi_os_set_prepare_sleep(int (* func)(u8 sleep_state,u32 pm1a_ctrl,u32 pm1b_ctrl))172209f98a82STang Liang void acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state,
172309f98a82STang Liang 			       u32 pm1a_ctrl, u32 pm1b_ctrl))
172409f98a82STang Liang {
172509f98a82STang Liang 	__acpi_os_prepare_sleep = func;
172609f98a82STang Liang }
172792d8aff3SYinghai Lu 
17280fc5e8f4SLv Zheng #if (ACPI_REDUCED_HARDWARE)
acpi_os_prepare_extended_sleep(u8 sleep_state,u32 val_a,u32 val_b)1729d6b47b12SBen Guthro acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a,
1730d6b47b12SBen Guthro 				  u32 val_b)
1731d6b47b12SBen Guthro {
1732d6b47b12SBen Guthro 	int rc = 0;
1733d6b47b12SBen Guthro 	if (__acpi_os_prepare_extended_sleep)
1734d6b47b12SBen Guthro 		rc = __acpi_os_prepare_extended_sleep(sleep_state,
1735d6b47b12SBen Guthro 					     val_a, val_b);
1736d6b47b12SBen Guthro 	if (rc < 0)
1737d6b47b12SBen Guthro 		return AE_ERROR;
1738d6b47b12SBen Guthro 	else if (rc > 0)
17390fc5e8f4SLv Zheng 		return AE_CTRL_TERMINATE;
1740d6b47b12SBen Guthro 
1741d6b47b12SBen Guthro 	return AE_OK;
1742d6b47b12SBen Guthro }
17430fc5e8f4SLv Zheng #else
acpi_os_prepare_extended_sleep(u8 sleep_state,u32 val_a,u32 val_b)17440fc5e8f4SLv Zheng acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a,
17450fc5e8f4SLv Zheng 				  u32 val_b)
17460fc5e8f4SLv Zheng {
17470fc5e8f4SLv Zheng 	return AE_OK;
17480fc5e8f4SLv Zheng }
17490fc5e8f4SLv Zheng #endif
1750d6b47b12SBen Guthro 
acpi_os_set_prepare_extended_sleep(int (* func)(u8 sleep_state,u32 val_a,u32 val_b))1751d6b47b12SBen Guthro void acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state,
1752d6b47b12SBen Guthro 			       u32 val_a, u32 val_b))
1753d6b47b12SBen Guthro {
1754d6b47b12SBen Guthro 	__acpi_os_prepare_extended_sleep = func;
1755d6b47b12SBen Guthro }
17560fc5e8f4SLv Zheng 
acpi_os_enter_sleep(u8 sleep_state,u32 reg_a_value,u32 reg_b_value)17570fc5e8f4SLv Zheng acpi_status acpi_os_enter_sleep(u8 sleep_state,
17580fc5e8f4SLv Zheng 				u32 reg_a_value, u32 reg_b_value)
17590fc5e8f4SLv Zheng {
17600fc5e8f4SLv Zheng 	acpi_status status;
17610fc5e8f4SLv Zheng 
17620fc5e8f4SLv Zheng 	if (acpi_gbl_reduced_hardware)
17630fc5e8f4SLv Zheng 		status = acpi_os_prepare_extended_sleep(sleep_state,
17640fc5e8f4SLv Zheng 							reg_a_value,
17650fc5e8f4SLv Zheng 							reg_b_value);
17660fc5e8f4SLv Zheng 	else
17670fc5e8f4SLv Zheng 		status = acpi_os_prepare_sleep(sleep_state,
17680fc5e8f4SLv Zheng 					       reg_a_value, reg_b_value);
17690fc5e8f4SLv Zheng 	return status;
17700fc5e8f4SLv Zheng }
1771