18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * acpi_osl.c - OS-dependent functions ($Revision: 83 $) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2000 Andrew Henroid 68c2ecf20Sopenharmony_ci * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com> 78c2ecf20Sopenharmony_ci * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> 88c2ecf20Sopenharmony_ci * Copyright (c) 2008 Intel Corporation 98c2ecf20Sopenharmony_ci * Author: Matthew Wilcox <willy@linux.intel.com> 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/slab.h> 158c2ecf20Sopenharmony_ci#include <linux/mm.h> 168c2ecf20Sopenharmony_ci#include <linux/highmem.h> 178c2ecf20Sopenharmony_ci#include <linux/lockdep.h> 188c2ecf20Sopenharmony_ci#include <linux/pci.h> 198c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 208c2ecf20Sopenharmony_ci#include <linux/kmod.h> 218c2ecf20Sopenharmony_ci#include <linux/delay.h> 228c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 238c2ecf20Sopenharmony_ci#include <linux/nmi.h> 248c2ecf20Sopenharmony_ci#include <linux/acpi.h> 258c2ecf20Sopenharmony_ci#include <linux/efi.h> 268c2ecf20Sopenharmony_ci#include <linux/ioport.h> 278c2ecf20Sopenharmony_ci#include <linux/list.h> 288c2ecf20Sopenharmony_ci#include <linux/jiffies.h> 298c2ecf20Sopenharmony_ci#include <linux/semaphore.h> 308c2ecf20Sopenharmony_ci#include <linux/security.h> 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_ci#include <asm/io.h> 338c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 348c2ecf20Sopenharmony_ci#include <linux/io-64-nonatomic-lo-hi.h> 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci#include "acpica/accommon.h" 378c2ecf20Sopenharmony_ci#include "acpica/acnamesp.h" 388c2ecf20Sopenharmony_ci#include "internal.h" 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci#define _COMPONENT ACPI_OS_SERVICES 418c2ecf20Sopenharmony_ciACPI_MODULE_NAME("osl"); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistruct acpi_os_dpc { 448c2ecf20Sopenharmony_ci acpi_osd_exec_callback function; 458c2ecf20Sopenharmony_ci void *context; 468c2ecf20Sopenharmony_ci struct work_struct work; 478c2ecf20Sopenharmony_ci}; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci#ifdef ENABLE_DEBUGGER 508c2ecf20Sopenharmony_ci#include <linux/kdb.h> 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci/* stuff for debugger support */ 538c2ecf20Sopenharmony_ciint acpi_in_debugger; 548c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_in_debugger); 558c2ecf20Sopenharmony_ci#endif /*ENABLE_DEBUGGER */ 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic int (*__acpi_os_prepare_sleep)(u8 sleep_state, u32 pm1a_ctrl, 588c2ecf20Sopenharmony_ci u32 pm1b_ctrl); 598c2ecf20Sopenharmony_cistatic int (*__acpi_os_prepare_extended_sleep)(u8 sleep_state, u32 val_a, 608c2ecf20Sopenharmony_ci u32 val_b); 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic acpi_osd_handler acpi_irq_handler; 638c2ecf20Sopenharmony_cistatic void *acpi_irq_context; 648c2ecf20Sopenharmony_cistatic struct workqueue_struct *kacpid_wq; 658c2ecf20Sopenharmony_cistatic struct workqueue_struct *kacpi_notify_wq; 668c2ecf20Sopenharmony_cistatic struct workqueue_struct *kacpi_hotplug_wq; 678c2ecf20Sopenharmony_cistatic bool acpi_os_initialized; 688c2ecf20Sopenharmony_ciunsigned int acpi_sci_irq = INVALID_ACPI_IRQ; 698c2ecf20Sopenharmony_cibool acpi_permanent_mmap = false; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci/* 728c2ecf20Sopenharmony_ci * This list of permanent mappings is for memory that may be accessed from 738c2ecf20Sopenharmony_ci * interrupt context, where we can't do the ioremap(). 748c2ecf20Sopenharmony_ci */ 758c2ecf20Sopenharmony_cistruct acpi_ioremap { 768c2ecf20Sopenharmony_ci struct list_head list; 778c2ecf20Sopenharmony_ci void __iomem *virt; 788c2ecf20Sopenharmony_ci acpi_physical_address phys; 798c2ecf20Sopenharmony_ci acpi_size size; 808c2ecf20Sopenharmony_ci union { 818c2ecf20Sopenharmony_ci unsigned long refcount; 828c2ecf20Sopenharmony_ci struct rcu_work rwork; 838c2ecf20Sopenharmony_ci } track; 848c2ecf20Sopenharmony_ci}; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic LIST_HEAD(acpi_ioremaps); 878c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(acpi_ioremap_lock); 888c2ecf20Sopenharmony_ci#define acpi_ioremap_lock_held() lock_is_held(&acpi_ioremap_lock.dep_map) 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic void __init acpi_request_region (struct acpi_generic_address *gas, 918c2ecf20Sopenharmony_ci unsigned int length, char *desc) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci u64 addr; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci /* Handle possible alignment issues */ 968c2ecf20Sopenharmony_ci memcpy(&addr, &gas->address, sizeof(addr)); 978c2ecf20Sopenharmony_ci if (!addr || !length) 988c2ecf20Sopenharmony_ci return; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci /* Resources are never freed */ 1018c2ecf20Sopenharmony_ci if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) 1028c2ecf20Sopenharmony_ci request_region(addr, length, desc); 1038c2ecf20Sopenharmony_ci else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) 1048c2ecf20Sopenharmony_ci request_mem_region(addr, length, desc); 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic int __init acpi_reserve_resources(void) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length, 1108c2ecf20Sopenharmony_ci "ACPI PM1a_EVT_BLK"); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci acpi_request_region(&acpi_gbl_FADT.xpm1b_event_block, acpi_gbl_FADT.pm1_event_length, 1138c2ecf20Sopenharmony_ci "ACPI PM1b_EVT_BLK"); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci acpi_request_region(&acpi_gbl_FADT.xpm1a_control_block, acpi_gbl_FADT.pm1_control_length, 1168c2ecf20Sopenharmony_ci "ACPI PM1a_CNT_BLK"); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci acpi_request_region(&acpi_gbl_FADT.xpm1b_control_block, acpi_gbl_FADT.pm1_control_length, 1198c2ecf20Sopenharmony_ci "ACPI PM1b_CNT_BLK"); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci if (acpi_gbl_FADT.pm_timer_length == 4) 1228c2ecf20Sopenharmony_ci acpi_request_region(&acpi_gbl_FADT.xpm_timer_block, 4, "ACPI PM_TMR"); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci acpi_request_region(&acpi_gbl_FADT.xpm2_control_block, acpi_gbl_FADT.pm2_control_length, 1258c2ecf20Sopenharmony_ci "ACPI PM2_CNT_BLK"); 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci /* Length of GPE blocks must be a non-negative multiple of 2 */ 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if (!(acpi_gbl_FADT.gpe0_block_length & 0x1)) 1308c2ecf20Sopenharmony_ci acpi_request_region(&acpi_gbl_FADT.xgpe0_block, 1318c2ecf20Sopenharmony_ci acpi_gbl_FADT.gpe0_block_length, "ACPI GPE0_BLK"); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (!(acpi_gbl_FADT.gpe1_block_length & 0x1)) 1348c2ecf20Sopenharmony_ci acpi_request_region(&acpi_gbl_FADT.xgpe1_block, 1358c2ecf20Sopenharmony_ci acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK"); 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci return 0; 1388c2ecf20Sopenharmony_ci} 1398c2ecf20Sopenharmony_cifs_initcall_sync(acpi_reserve_resources); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_civoid acpi_os_printf(const char *fmt, ...) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci va_list args; 1448c2ecf20Sopenharmony_ci va_start(args, fmt); 1458c2ecf20Sopenharmony_ci acpi_os_vprintf(fmt, args); 1468c2ecf20Sopenharmony_ci va_end(args); 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_os_printf); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_civoid acpi_os_vprintf(const char *fmt, va_list args) 1518c2ecf20Sopenharmony_ci{ 1528c2ecf20Sopenharmony_ci static char buffer[512]; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci vsprintf(buffer, fmt, args); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci#ifdef ENABLE_DEBUGGER 1578c2ecf20Sopenharmony_ci if (acpi_in_debugger) { 1588c2ecf20Sopenharmony_ci kdb_printf("%s", buffer); 1598c2ecf20Sopenharmony_ci } else { 1608c2ecf20Sopenharmony_ci if (printk_get_level(buffer)) 1618c2ecf20Sopenharmony_ci printk("%s", buffer); 1628c2ecf20Sopenharmony_ci else 1638c2ecf20Sopenharmony_ci printk(KERN_CONT "%s", buffer); 1648c2ecf20Sopenharmony_ci } 1658c2ecf20Sopenharmony_ci#else 1668c2ecf20Sopenharmony_ci if (acpi_debugger_write_log(buffer) < 0) { 1678c2ecf20Sopenharmony_ci if (printk_get_level(buffer)) 1688c2ecf20Sopenharmony_ci printk("%s", buffer); 1698c2ecf20Sopenharmony_ci else 1708c2ecf20Sopenharmony_ci printk(KERN_CONT "%s", buffer); 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci#endif 1738c2ecf20Sopenharmony_ci} 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci#ifdef CONFIG_KEXEC 1768c2ecf20Sopenharmony_cistatic unsigned long acpi_rsdp; 1778c2ecf20Sopenharmony_cistatic int __init setup_acpi_rsdp(char *arg) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci return kstrtoul(arg, 16, &acpi_rsdp); 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ciearly_param("acpi_rsdp", setup_acpi_rsdp); 1828c2ecf20Sopenharmony_ci#endif 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ciacpi_physical_address __init acpi_os_get_root_pointer(void) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci acpi_physical_address pa; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci#ifdef CONFIG_KEXEC 1898c2ecf20Sopenharmony_ci /* 1908c2ecf20Sopenharmony_ci * We may have been provided with an RSDP on the command line, 1918c2ecf20Sopenharmony_ci * but if a malicious user has done so they may be pointing us 1928c2ecf20Sopenharmony_ci * at modified ACPI tables that could alter kernel behaviour - 1938c2ecf20Sopenharmony_ci * so, we check the lockdown status before making use of 1948c2ecf20Sopenharmony_ci * it. If we trust it then also stash it in an architecture 1958c2ecf20Sopenharmony_ci * specific location (if appropriate) so it can be carried 1968c2ecf20Sopenharmony_ci * over further kexec()s. 1978c2ecf20Sopenharmony_ci */ 1988c2ecf20Sopenharmony_ci if (acpi_rsdp && !security_locked_down(LOCKDOWN_ACPI_TABLES)) { 1998c2ecf20Sopenharmony_ci acpi_arch_set_root_pointer(acpi_rsdp); 2008c2ecf20Sopenharmony_ci return acpi_rsdp; 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci#endif 2038c2ecf20Sopenharmony_ci pa = acpi_arch_get_root_pointer(); 2048c2ecf20Sopenharmony_ci if (pa) 2058c2ecf20Sopenharmony_ci return pa; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci if (efi_enabled(EFI_CONFIG_TABLES)) { 2088c2ecf20Sopenharmony_ci if (efi.acpi20 != EFI_INVALID_TABLE_ADDR) 2098c2ecf20Sopenharmony_ci return efi.acpi20; 2108c2ecf20Sopenharmony_ci if (efi.acpi != EFI_INVALID_TABLE_ADDR) 2118c2ecf20Sopenharmony_ci return efi.acpi; 2128c2ecf20Sopenharmony_ci pr_err(PREFIX "System description tables not found\n"); 2138c2ecf20Sopenharmony_ci } else if (IS_ENABLED(CONFIG_ACPI_LEGACY_TABLES_LOOKUP)) { 2148c2ecf20Sopenharmony_ci acpi_find_root_pointer(&pa); 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci return pa; 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci/* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */ 2218c2ecf20Sopenharmony_cistatic struct acpi_ioremap * 2228c2ecf20Sopenharmony_ciacpi_map_lookup(acpi_physical_address phys, acpi_size size) 2238c2ecf20Sopenharmony_ci{ 2248c2ecf20Sopenharmony_ci struct acpi_ioremap *map; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci list_for_each_entry_rcu(map, &acpi_ioremaps, list, acpi_ioremap_lock_held()) 2278c2ecf20Sopenharmony_ci if (map->phys <= phys && 2288c2ecf20Sopenharmony_ci phys + size <= map->phys + map->size) 2298c2ecf20Sopenharmony_ci return map; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci return NULL; 2328c2ecf20Sopenharmony_ci} 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci/* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */ 2358c2ecf20Sopenharmony_cistatic void __iomem * 2368c2ecf20Sopenharmony_ciacpi_map_vaddr_lookup(acpi_physical_address phys, unsigned int size) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci struct acpi_ioremap *map; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci map = acpi_map_lookup(phys, size); 2418c2ecf20Sopenharmony_ci if (map) 2428c2ecf20Sopenharmony_ci return map->virt + (phys - map->phys); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci return NULL; 2458c2ecf20Sopenharmony_ci} 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_civoid __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct acpi_ioremap *map; 2508c2ecf20Sopenharmony_ci void __iomem *virt = NULL; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci mutex_lock(&acpi_ioremap_lock); 2538c2ecf20Sopenharmony_ci map = acpi_map_lookup(phys, size); 2548c2ecf20Sopenharmony_ci if (map) { 2558c2ecf20Sopenharmony_ci virt = map->virt + (phys - map->phys); 2568c2ecf20Sopenharmony_ci map->track.refcount++; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci mutex_unlock(&acpi_ioremap_lock); 2598c2ecf20Sopenharmony_ci return virt; 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_os_get_iomem); 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci/* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */ 2648c2ecf20Sopenharmony_cistatic struct acpi_ioremap * 2658c2ecf20Sopenharmony_ciacpi_map_lookup_virt(void __iomem *virt, acpi_size size) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci struct acpi_ioremap *map; 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci list_for_each_entry_rcu(map, &acpi_ioremaps, list, acpi_ioremap_lock_held()) 2708c2ecf20Sopenharmony_ci if (map->virt <= virt && 2718c2ecf20Sopenharmony_ci virt + size <= map->virt + map->size) 2728c2ecf20Sopenharmony_ci return map; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci return NULL; 2758c2ecf20Sopenharmony_ci} 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci#if defined(CONFIG_IA64) || defined(CONFIG_ARM64) 2788c2ecf20Sopenharmony_ci/* ioremap will take care of cache attributes */ 2798c2ecf20Sopenharmony_ci#define should_use_kmap(pfn) 0 2808c2ecf20Sopenharmony_ci#else 2818c2ecf20Sopenharmony_ci#define should_use_kmap(pfn) page_is_ram(pfn) 2828c2ecf20Sopenharmony_ci#endif 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_cistatic void __iomem *acpi_map(acpi_physical_address pg_off, unsigned long pg_sz) 2858c2ecf20Sopenharmony_ci{ 2868c2ecf20Sopenharmony_ci unsigned long pfn; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci pfn = pg_off >> PAGE_SHIFT; 2898c2ecf20Sopenharmony_ci if (should_use_kmap(pfn)) { 2908c2ecf20Sopenharmony_ci if (pg_sz > PAGE_SIZE) 2918c2ecf20Sopenharmony_ci return NULL; 2928c2ecf20Sopenharmony_ci return (void __iomem __force *)kmap(pfn_to_page(pfn)); 2938c2ecf20Sopenharmony_ci } else 2948c2ecf20Sopenharmony_ci return acpi_os_ioremap(pg_off, pg_sz); 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic void acpi_unmap(acpi_physical_address pg_off, void __iomem *vaddr) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci unsigned long pfn; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci pfn = pg_off >> PAGE_SHIFT; 3028c2ecf20Sopenharmony_ci if (should_use_kmap(pfn)) 3038c2ecf20Sopenharmony_ci kunmap(pfn_to_page(pfn)); 3048c2ecf20Sopenharmony_ci else 3058c2ecf20Sopenharmony_ci iounmap(vaddr); 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci/** 3098c2ecf20Sopenharmony_ci * acpi_os_map_iomem - Get a virtual address for a given physical address range. 3108c2ecf20Sopenharmony_ci * @phys: Start of the physical address range to map. 3118c2ecf20Sopenharmony_ci * @size: Size of the physical address range to map. 3128c2ecf20Sopenharmony_ci * 3138c2ecf20Sopenharmony_ci * Look up the given physical address range in the list of existing ACPI memory 3148c2ecf20Sopenharmony_ci * mappings. If found, get a reference to it and return a pointer to it (its 3158c2ecf20Sopenharmony_ci * virtual address). If not found, map it, add it to that list and return a 3168c2ecf20Sopenharmony_ci * pointer to it. 3178c2ecf20Sopenharmony_ci * 3188c2ecf20Sopenharmony_ci * During early init (when acpi_permanent_mmap has not been set yet) this 3198c2ecf20Sopenharmony_ci * routine simply calls __acpi_map_table() to get the job done. 3208c2ecf20Sopenharmony_ci */ 3218c2ecf20Sopenharmony_civoid __iomem __ref 3228c2ecf20Sopenharmony_ci*acpi_os_map_iomem(acpi_physical_address phys, acpi_size size) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci struct acpi_ioremap *map; 3258c2ecf20Sopenharmony_ci void __iomem *virt; 3268c2ecf20Sopenharmony_ci acpi_physical_address pg_off; 3278c2ecf20Sopenharmony_ci acpi_size pg_sz; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci if (phys > ULONG_MAX) { 3308c2ecf20Sopenharmony_ci printk(KERN_ERR PREFIX "Cannot map memory that high\n"); 3318c2ecf20Sopenharmony_ci return NULL; 3328c2ecf20Sopenharmony_ci } 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci if (!acpi_permanent_mmap) 3358c2ecf20Sopenharmony_ci return __acpi_map_table((unsigned long)phys, size); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci mutex_lock(&acpi_ioremap_lock); 3388c2ecf20Sopenharmony_ci /* Check if there's a suitable mapping already. */ 3398c2ecf20Sopenharmony_ci map = acpi_map_lookup(phys, size); 3408c2ecf20Sopenharmony_ci if (map) { 3418c2ecf20Sopenharmony_ci map->track.refcount++; 3428c2ecf20Sopenharmony_ci goto out; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci map = kzalloc(sizeof(*map), GFP_KERNEL); 3468c2ecf20Sopenharmony_ci if (!map) { 3478c2ecf20Sopenharmony_ci mutex_unlock(&acpi_ioremap_lock); 3488c2ecf20Sopenharmony_ci return NULL; 3498c2ecf20Sopenharmony_ci } 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci pg_off = round_down(phys, PAGE_SIZE); 3528c2ecf20Sopenharmony_ci pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off; 3538c2ecf20Sopenharmony_ci virt = acpi_map(phys, size); 3548c2ecf20Sopenharmony_ci if (!virt) { 3558c2ecf20Sopenharmony_ci mutex_unlock(&acpi_ioremap_lock); 3568c2ecf20Sopenharmony_ci kfree(map); 3578c2ecf20Sopenharmony_ci return NULL; 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&map->list); 3618c2ecf20Sopenharmony_ci map->virt = (void __iomem __force *)((unsigned long)virt & PAGE_MASK); 3628c2ecf20Sopenharmony_ci map->phys = pg_off; 3638c2ecf20Sopenharmony_ci map->size = pg_sz; 3648c2ecf20Sopenharmony_ci map->track.refcount = 1; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci list_add_tail_rcu(&map->list, &acpi_ioremaps); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ciout: 3698c2ecf20Sopenharmony_ci mutex_unlock(&acpi_ioremap_lock); 3708c2ecf20Sopenharmony_ci return map->virt + (phys - map->phys); 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_os_map_iomem); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_civoid *__ref acpi_os_map_memory(acpi_physical_address phys, acpi_size size) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci return (void *)acpi_os_map_iomem(phys, size); 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_os_map_memory); 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_cistatic void acpi_os_map_remove(struct work_struct *work) 3818c2ecf20Sopenharmony_ci{ 3828c2ecf20Sopenharmony_ci struct acpi_ioremap *map = container_of(to_rcu_work(work), 3838c2ecf20Sopenharmony_ci struct acpi_ioremap, 3848c2ecf20Sopenharmony_ci track.rwork); 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci acpi_unmap(map->phys, map->virt); 3878c2ecf20Sopenharmony_ci kfree(map); 3888c2ecf20Sopenharmony_ci} 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci/* Must be called with mutex_lock(&acpi_ioremap_lock) */ 3918c2ecf20Sopenharmony_cistatic void acpi_os_drop_map_ref(struct acpi_ioremap *map) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci if (--map->track.refcount) 3948c2ecf20Sopenharmony_ci return; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci list_del_rcu(&map->list); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci INIT_RCU_WORK(&map->track.rwork, acpi_os_map_remove); 3998c2ecf20Sopenharmony_ci queue_rcu_work(system_wq, &map->track.rwork); 4008c2ecf20Sopenharmony_ci} 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci/** 4038c2ecf20Sopenharmony_ci * acpi_os_unmap_iomem - Drop a memory mapping reference. 4048c2ecf20Sopenharmony_ci * @virt: Start of the address range to drop a reference to. 4058c2ecf20Sopenharmony_ci * @size: Size of the address range to drop a reference to. 4068c2ecf20Sopenharmony_ci * 4078c2ecf20Sopenharmony_ci * Look up the given virtual address range in the list of existing ACPI memory 4088c2ecf20Sopenharmony_ci * mappings, drop a reference to it and if there are no more active references 4098c2ecf20Sopenharmony_ci * to it, queue it up for later removal. 4108c2ecf20Sopenharmony_ci * 4118c2ecf20Sopenharmony_ci * During early init (when acpi_permanent_mmap has not been set yet) this 4128c2ecf20Sopenharmony_ci * routine simply calls __acpi_unmap_table() to get the job done. Since 4138c2ecf20Sopenharmony_ci * __acpi_unmap_table() is an __init function, the __ref annotation is needed 4148c2ecf20Sopenharmony_ci * here. 4158c2ecf20Sopenharmony_ci */ 4168c2ecf20Sopenharmony_civoid __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci struct acpi_ioremap *map; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci if (!acpi_permanent_mmap) { 4218c2ecf20Sopenharmony_ci __acpi_unmap_table(virt, size); 4228c2ecf20Sopenharmony_ci return; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci mutex_lock(&acpi_ioremap_lock); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci map = acpi_map_lookup_virt(virt, size); 4288c2ecf20Sopenharmony_ci if (!map) { 4298c2ecf20Sopenharmony_ci mutex_unlock(&acpi_ioremap_lock); 4308c2ecf20Sopenharmony_ci WARN(true, PREFIX "%s: bad address %p\n", __func__, virt); 4318c2ecf20Sopenharmony_ci return; 4328c2ecf20Sopenharmony_ci } 4338c2ecf20Sopenharmony_ci acpi_os_drop_map_ref(map); 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci mutex_unlock(&acpi_ioremap_lock); 4368c2ecf20Sopenharmony_ci} 4378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_os_unmap_iomem); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci/** 4408c2ecf20Sopenharmony_ci * acpi_os_unmap_memory - Drop a memory mapping reference. 4418c2ecf20Sopenharmony_ci * @virt: Start of the address range to drop a reference to. 4428c2ecf20Sopenharmony_ci * @size: Size of the address range to drop a reference to. 4438c2ecf20Sopenharmony_ci */ 4448c2ecf20Sopenharmony_civoid __ref acpi_os_unmap_memory(void *virt, acpi_size size) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci acpi_os_unmap_iomem((void __iomem *)virt, size); 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_os_unmap_memory); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_civoid __iomem *acpi_os_map_generic_address(struct acpi_generic_address *gas) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci u64 addr; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) 4558c2ecf20Sopenharmony_ci return NULL; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* Handle possible alignment issues */ 4588c2ecf20Sopenharmony_ci memcpy(&addr, &gas->address, sizeof(addr)); 4598c2ecf20Sopenharmony_ci if (!addr || !gas->bit_width) 4608c2ecf20Sopenharmony_ci return NULL; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci return acpi_os_map_iomem(addr, gas->bit_width / 8); 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_os_map_generic_address); 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_civoid acpi_os_unmap_generic_address(struct acpi_generic_address *gas) 4678c2ecf20Sopenharmony_ci{ 4688c2ecf20Sopenharmony_ci u64 addr; 4698c2ecf20Sopenharmony_ci struct acpi_ioremap *map; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) 4728c2ecf20Sopenharmony_ci return; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci /* Handle possible alignment issues */ 4758c2ecf20Sopenharmony_ci memcpy(&addr, &gas->address, sizeof(addr)); 4768c2ecf20Sopenharmony_ci if (!addr || !gas->bit_width) 4778c2ecf20Sopenharmony_ci return; 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci mutex_lock(&acpi_ioremap_lock); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci map = acpi_map_lookup(addr, gas->bit_width / 8); 4828c2ecf20Sopenharmony_ci if (!map) { 4838c2ecf20Sopenharmony_ci mutex_unlock(&acpi_ioremap_lock); 4848c2ecf20Sopenharmony_ci return; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci acpi_os_drop_map_ref(map); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci mutex_unlock(&acpi_ioremap_lock); 4898c2ecf20Sopenharmony_ci} 4908c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_os_unmap_generic_address); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci#ifdef ACPI_FUTURE_USAGE 4938c2ecf20Sopenharmony_ciacpi_status 4948c2ecf20Sopenharmony_ciacpi_os_get_physical_address(void *virt, acpi_physical_address * phys) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci if (!phys || !virt) 4978c2ecf20Sopenharmony_ci return AE_BAD_PARAMETER; 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci *phys = virt_to_phys(virt); 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci return AE_OK; 5028c2ecf20Sopenharmony_ci} 5038c2ecf20Sopenharmony_ci#endif 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI_REV_OVERRIDE_POSSIBLE 5068c2ecf20Sopenharmony_cistatic bool acpi_rev_override; 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ciint __init acpi_rev_override_setup(char *str) 5098c2ecf20Sopenharmony_ci{ 5108c2ecf20Sopenharmony_ci acpi_rev_override = true; 5118c2ecf20Sopenharmony_ci return 1; 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci__setup("acpi_rev_override", acpi_rev_override_setup); 5148c2ecf20Sopenharmony_ci#else 5158c2ecf20Sopenharmony_ci#define acpi_rev_override false 5168c2ecf20Sopenharmony_ci#endif 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci#define ACPI_MAX_OVERRIDE_LEN 100 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_cistatic char acpi_os_name[ACPI_MAX_OVERRIDE_LEN]; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ciacpi_status 5238c2ecf20Sopenharmony_ciacpi_os_predefined_override(const struct acpi_predefined_names *init_val, 5248c2ecf20Sopenharmony_ci acpi_string *new_val) 5258c2ecf20Sopenharmony_ci{ 5268c2ecf20Sopenharmony_ci if (!init_val || !new_val) 5278c2ecf20Sopenharmony_ci return AE_BAD_PARAMETER; 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci *new_val = NULL; 5308c2ecf20Sopenharmony_ci if (!memcmp(init_val->name, "_OS_", 4) && strlen(acpi_os_name)) { 5318c2ecf20Sopenharmony_ci printk(KERN_INFO PREFIX "Overriding _OS definition to '%s'\n", 5328c2ecf20Sopenharmony_ci acpi_os_name); 5338c2ecf20Sopenharmony_ci *new_val = acpi_os_name; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci if (!memcmp(init_val->name, "_REV", 4) && acpi_rev_override) { 5378c2ecf20Sopenharmony_ci printk(KERN_INFO PREFIX "Overriding _REV return value to 5\n"); 5388c2ecf20Sopenharmony_ci *new_val = (char *)5; 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci return AE_OK; 5428c2ecf20Sopenharmony_ci} 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_cistatic irqreturn_t acpi_irq(int irq, void *dev_id) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci u32 handled; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci handled = (*acpi_irq_handler) (acpi_irq_context); 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci if (handled) { 5518c2ecf20Sopenharmony_ci acpi_irq_handled++; 5528c2ecf20Sopenharmony_ci return IRQ_HANDLED; 5538c2ecf20Sopenharmony_ci } else { 5548c2ecf20Sopenharmony_ci acpi_irq_not_handled++; 5558c2ecf20Sopenharmony_ci return IRQ_NONE; 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci} 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ciacpi_status 5608c2ecf20Sopenharmony_ciacpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler, 5618c2ecf20Sopenharmony_ci void *context) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci unsigned int irq; 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci acpi_irq_stats_init(); 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci /* 5688c2ecf20Sopenharmony_ci * ACPI interrupts different from the SCI in our copy of the FADT are 5698c2ecf20Sopenharmony_ci * not supported. 5708c2ecf20Sopenharmony_ci */ 5718c2ecf20Sopenharmony_ci if (gsi != acpi_gbl_FADT.sci_interrupt) 5728c2ecf20Sopenharmony_ci return AE_BAD_PARAMETER; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (acpi_irq_handler) 5758c2ecf20Sopenharmony_ci return AE_ALREADY_ACQUIRED; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci if (acpi_gsi_to_irq(gsi, &irq) < 0) { 5788c2ecf20Sopenharmony_ci printk(KERN_ERR PREFIX "SCI (ACPI GSI %d) not registered\n", 5798c2ecf20Sopenharmony_ci gsi); 5808c2ecf20Sopenharmony_ci return AE_OK; 5818c2ecf20Sopenharmony_ci } 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci acpi_irq_handler = handler; 5848c2ecf20Sopenharmony_ci acpi_irq_context = context; 5858c2ecf20Sopenharmony_ci if (request_irq(irq, acpi_irq, IRQF_SHARED, "acpi", acpi_irq)) { 5868c2ecf20Sopenharmony_ci printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq); 5878c2ecf20Sopenharmony_ci acpi_irq_handler = NULL; 5888c2ecf20Sopenharmony_ci return AE_NOT_ACQUIRED; 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci acpi_sci_irq = irq; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci return AE_OK; 5938c2ecf20Sopenharmony_ci} 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ciacpi_status acpi_os_remove_interrupt_handler(u32 gsi, acpi_osd_handler handler) 5968c2ecf20Sopenharmony_ci{ 5978c2ecf20Sopenharmony_ci if (gsi != acpi_gbl_FADT.sci_interrupt || !acpi_sci_irq_valid()) 5988c2ecf20Sopenharmony_ci return AE_BAD_PARAMETER; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci free_irq(acpi_sci_irq, acpi_irq); 6018c2ecf20Sopenharmony_ci acpi_irq_handler = NULL; 6028c2ecf20Sopenharmony_ci acpi_sci_irq = INVALID_ACPI_IRQ; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci return AE_OK; 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci/* 6088c2ecf20Sopenharmony_ci * Running in interpreter thread context, safe to sleep 6098c2ecf20Sopenharmony_ci */ 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_civoid acpi_os_sleep(u64 ms) 6128c2ecf20Sopenharmony_ci{ 6138c2ecf20Sopenharmony_ci msleep(ms); 6148c2ecf20Sopenharmony_ci} 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_civoid acpi_os_stall(u32 us) 6178c2ecf20Sopenharmony_ci{ 6188c2ecf20Sopenharmony_ci while (us) { 6198c2ecf20Sopenharmony_ci u32 delay = 1000; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_ci if (delay > us) 6228c2ecf20Sopenharmony_ci delay = us; 6238c2ecf20Sopenharmony_ci udelay(delay); 6248c2ecf20Sopenharmony_ci touch_nmi_watchdog(); 6258c2ecf20Sopenharmony_ci us -= delay; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci} 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci/* 6308c2ecf20Sopenharmony_ci * Support ACPI 3.0 AML Timer operand. Returns a 64-bit free-running, 6318c2ecf20Sopenharmony_ci * monotonically increasing timer with 100ns granularity. Do not use 6328c2ecf20Sopenharmony_ci * ktime_get() to implement this function because this function may get 6338c2ecf20Sopenharmony_ci * called after timekeeping has been suspended. Note: calling this function 6348c2ecf20Sopenharmony_ci * after timekeeping has been suspended may lead to unexpected results 6358c2ecf20Sopenharmony_ci * because when timekeeping is suspended the jiffies counter is not 6368c2ecf20Sopenharmony_ci * incremented. See also timekeeping_suspend(). 6378c2ecf20Sopenharmony_ci */ 6388c2ecf20Sopenharmony_ciu64 acpi_os_get_timer(void) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci return (get_jiffies_64() - INITIAL_JIFFIES) * 6418c2ecf20Sopenharmony_ci (ACPI_100NSEC_PER_SEC / HZ); 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ciacpi_status acpi_os_read_port(acpi_io_address port, u32 * value, u32 width) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci u32 dummy; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci if (!value) 6498c2ecf20Sopenharmony_ci value = &dummy; 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci *value = 0; 6528c2ecf20Sopenharmony_ci if (width <= 8) { 6538c2ecf20Sopenharmony_ci *(u8 *) value = inb(port); 6548c2ecf20Sopenharmony_ci } else if (width <= 16) { 6558c2ecf20Sopenharmony_ci *(u16 *) value = inw(port); 6568c2ecf20Sopenharmony_ci } else if (width <= 32) { 6578c2ecf20Sopenharmony_ci *(u32 *) value = inl(port); 6588c2ecf20Sopenharmony_ci } else { 6598c2ecf20Sopenharmony_ci BUG(); 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci return AE_OK; 6638c2ecf20Sopenharmony_ci} 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_os_read_port); 6668c2ecf20Sopenharmony_ci 6678c2ecf20Sopenharmony_ciacpi_status acpi_os_write_port(acpi_io_address port, u32 value, u32 width) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci if (width <= 8) { 6708c2ecf20Sopenharmony_ci outb(value, port); 6718c2ecf20Sopenharmony_ci } else if (width <= 16) { 6728c2ecf20Sopenharmony_ci outw(value, port); 6738c2ecf20Sopenharmony_ci } else if (width <= 32) { 6748c2ecf20Sopenharmony_ci outl(value, port); 6758c2ecf20Sopenharmony_ci } else { 6768c2ecf20Sopenharmony_ci BUG(); 6778c2ecf20Sopenharmony_ci } 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci return AE_OK; 6808c2ecf20Sopenharmony_ci} 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_os_write_port); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ciint acpi_os_read_iomem(void __iomem *virt_addr, u64 *value, u32 width) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci switch (width) { 6888c2ecf20Sopenharmony_ci case 8: 6898c2ecf20Sopenharmony_ci *(u8 *) value = readb(virt_addr); 6908c2ecf20Sopenharmony_ci break; 6918c2ecf20Sopenharmony_ci case 16: 6928c2ecf20Sopenharmony_ci *(u16 *) value = readw(virt_addr); 6938c2ecf20Sopenharmony_ci break; 6948c2ecf20Sopenharmony_ci case 32: 6958c2ecf20Sopenharmony_ci *(u32 *) value = readl(virt_addr); 6968c2ecf20Sopenharmony_ci break; 6978c2ecf20Sopenharmony_ci case 64: 6988c2ecf20Sopenharmony_ci *(u64 *) value = readq(virt_addr); 6998c2ecf20Sopenharmony_ci break; 7008c2ecf20Sopenharmony_ci default: 7018c2ecf20Sopenharmony_ci return -EINVAL; 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci return 0; 7058c2ecf20Sopenharmony_ci} 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ciacpi_status 7088c2ecf20Sopenharmony_ciacpi_os_read_memory(acpi_physical_address phys_addr, u64 *value, u32 width) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci void __iomem *virt_addr; 7118c2ecf20Sopenharmony_ci unsigned int size = width / 8; 7128c2ecf20Sopenharmony_ci bool unmap = false; 7138c2ecf20Sopenharmony_ci u64 dummy; 7148c2ecf20Sopenharmony_ci int error; 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci rcu_read_lock(); 7178c2ecf20Sopenharmony_ci virt_addr = acpi_map_vaddr_lookup(phys_addr, size); 7188c2ecf20Sopenharmony_ci if (!virt_addr) { 7198c2ecf20Sopenharmony_ci rcu_read_unlock(); 7208c2ecf20Sopenharmony_ci virt_addr = acpi_os_ioremap(phys_addr, size); 7218c2ecf20Sopenharmony_ci if (!virt_addr) 7228c2ecf20Sopenharmony_ci return AE_BAD_ADDRESS; 7238c2ecf20Sopenharmony_ci unmap = true; 7248c2ecf20Sopenharmony_ci } 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci if (!value) 7278c2ecf20Sopenharmony_ci value = &dummy; 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci error = acpi_os_read_iomem(virt_addr, value, width); 7308c2ecf20Sopenharmony_ci BUG_ON(error); 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci if (unmap) 7338c2ecf20Sopenharmony_ci iounmap(virt_addr); 7348c2ecf20Sopenharmony_ci else 7358c2ecf20Sopenharmony_ci rcu_read_unlock(); 7368c2ecf20Sopenharmony_ci 7378c2ecf20Sopenharmony_ci return AE_OK; 7388c2ecf20Sopenharmony_ci} 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ciacpi_status 7418c2ecf20Sopenharmony_ciacpi_os_write_memory(acpi_physical_address phys_addr, u64 value, u32 width) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci void __iomem *virt_addr; 7448c2ecf20Sopenharmony_ci unsigned int size = width / 8; 7458c2ecf20Sopenharmony_ci bool unmap = false; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci rcu_read_lock(); 7488c2ecf20Sopenharmony_ci virt_addr = acpi_map_vaddr_lookup(phys_addr, size); 7498c2ecf20Sopenharmony_ci if (!virt_addr) { 7508c2ecf20Sopenharmony_ci rcu_read_unlock(); 7518c2ecf20Sopenharmony_ci virt_addr = acpi_os_ioremap(phys_addr, size); 7528c2ecf20Sopenharmony_ci if (!virt_addr) 7538c2ecf20Sopenharmony_ci return AE_BAD_ADDRESS; 7548c2ecf20Sopenharmony_ci unmap = true; 7558c2ecf20Sopenharmony_ci } 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci switch (width) { 7588c2ecf20Sopenharmony_ci case 8: 7598c2ecf20Sopenharmony_ci writeb(value, virt_addr); 7608c2ecf20Sopenharmony_ci break; 7618c2ecf20Sopenharmony_ci case 16: 7628c2ecf20Sopenharmony_ci writew(value, virt_addr); 7638c2ecf20Sopenharmony_ci break; 7648c2ecf20Sopenharmony_ci case 32: 7658c2ecf20Sopenharmony_ci writel(value, virt_addr); 7668c2ecf20Sopenharmony_ci break; 7678c2ecf20Sopenharmony_ci case 64: 7688c2ecf20Sopenharmony_ci writeq(value, virt_addr); 7698c2ecf20Sopenharmony_ci break; 7708c2ecf20Sopenharmony_ci default: 7718c2ecf20Sopenharmony_ci BUG(); 7728c2ecf20Sopenharmony_ci } 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci if (unmap) 7758c2ecf20Sopenharmony_ci iounmap(virt_addr); 7768c2ecf20Sopenharmony_ci else 7778c2ecf20Sopenharmony_ci rcu_read_unlock(); 7788c2ecf20Sopenharmony_ci 7798c2ecf20Sopenharmony_ci return AE_OK; 7808c2ecf20Sopenharmony_ci} 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI 7838c2ecf20Sopenharmony_ciacpi_status 7848c2ecf20Sopenharmony_ciacpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, 7858c2ecf20Sopenharmony_ci u64 *value, u32 width) 7868c2ecf20Sopenharmony_ci{ 7878c2ecf20Sopenharmony_ci int result, size; 7888c2ecf20Sopenharmony_ci u32 value32; 7898c2ecf20Sopenharmony_ci 7908c2ecf20Sopenharmony_ci if (!value) 7918c2ecf20Sopenharmony_ci return AE_BAD_PARAMETER; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci switch (width) { 7948c2ecf20Sopenharmony_ci case 8: 7958c2ecf20Sopenharmony_ci size = 1; 7968c2ecf20Sopenharmony_ci break; 7978c2ecf20Sopenharmony_ci case 16: 7988c2ecf20Sopenharmony_ci size = 2; 7998c2ecf20Sopenharmony_ci break; 8008c2ecf20Sopenharmony_ci case 32: 8018c2ecf20Sopenharmony_ci size = 4; 8028c2ecf20Sopenharmony_ci break; 8038c2ecf20Sopenharmony_ci default: 8048c2ecf20Sopenharmony_ci return AE_ERROR; 8058c2ecf20Sopenharmony_ci } 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci result = raw_pci_read(pci_id->segment, pci_id->bus, 8088c2ecf20Sopenharmony_ci PCI_DEVFN(pci_id->device, pci_id->function), 8098c2ecf20Sopenharmony_ci reg, size, &value32); 8108c2ecf20Sopenharmony_ci *value = value32; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci return (result ? AE_ERROR : AE_OK); 8138c2ecf20Sopenharmony_ci} 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_ciacpi_status 8168c2ecf20Sopenharmony_ciacpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg, 8178c2ecf20Sopenharmony_ci u64 value, u32 width) 8188c2ecf20Sopenharmony_ci{ 8198c2ecf20Sopenharmony_ci int result, size; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci switch (width) { 8228c2ecf20Sopenharmony_ci case 8: 8238c2ecf20Sopenharmony_ci size = 1; 8248c2ecf20Sopenharmony_ci break; 8258c2ecf20Sopenharmony_ci case 16: 8268c2ecf20Sopenharmony_ci size = 2; 8278c2ecf20Sopenharmony_ci break; 8288c2ecf20Sopenharmony_ci case 32: 8298c2ecf20Sopenharmony_ci size = 4; 8308c2ecf20Sopenharmony_ci break; 8318c2ecf20Sopenharmony_ci default: 8328c2ecf20Sopenharmony_ci return AE_ERROR; 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci result = raw_pci_write(pci_id->segment, pci_id->bus, 8368c2ecf20Sopenharmony_ci PCI_DEVFN(pci_id->device, pci_id->function), 8378c2ecf20Sopenharmony_ci reg, size, value); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci return (result ? AE_ERROR : AE_OK); 8408c2ecf20Sopenharmony_ci} 8418c2ecf20Sopenharmony_ci#endif 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_cistatic void acpi_os_execute_deferred(struct work_struct *work) 8448c2ecf20Sopenharmony_ci{ 8458c2ecf20Sopenharmony_ci struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci dpc->function(dpc->context); 8488c2ecf20Sopenharmony_ci kfree(dpc); 8498c2ecf20Sopenharmony_ci} 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI_DEBUGGER 8528c2ecf20Sopenharmony_cistatic struct acpi_debugger acpi_debugger; 8538c2ecf20Sopenharmony_cistatic bool acpi_debugger_initialized; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ciint acpi_register_debugger(struct module *owner, 8568c2ecf20Sopenharmony_ci const struct acpi_debugger_ops *ops) 8578c2ecf20Sopenharmony_ci{ 8588c2ecf20Sopenharmony_ci int ret = 0; 8598c2ecf20Sopenharmony_ci 8608c2ecf20Sopenharmony_ci mutex_lock(&acpi_debugger.lock); 8618c2ecf20Sopenharmony_ci if (acpi_debugger.ops) { 8628c2ecf20Sopenharmony_ci ret = -EBUSY; 8638c2ecf20Sopenharmony_ci goto err_lock; 8648c2ecf20Sopenharmony_ci } 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci acpi_debugger.owner = owner; 8678c2ecf20Sopenharmony_ci acpi_debugger.ops = ops; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_cierr_lock: 8708c2ecf20Sopenharmony_ci mutex_unlock(&acpi_debugger.lock); 8718c2ecf20Sopenharmony_ci return ret; 8728c2ecf20Sopenharmony_ci} 8738c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_register_debugger); 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_civoid acpi_unregister_debugger(const struct acpi_debugger_ops *ops) 8768c2ecf20Sopenharmony_ci{ 8778c2ecf20Sopenharmony_ci mutex_lock(&acpi_debugger.lock); 8788c2ecf20Sopenharmony_ci if (ops == acpi_debugger.ops) { 8798c2ecf20Sopenharmony_ci acpi_debugger.ops = NULL; 8808c2ecf20Sopenharmony_ci acpi_debugger.owner = NULL; 8818c2ecf20Sopenharmony_ci } 8828c2ecf20Sopenharmony_ci mutex_unlock(&acpi_debugger.lock); 8838c2ecf20Sopenharmony_ci} 8848c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_unregister_debugger); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ciint acpi_debugger_create_thread(acpi_osd_exec_callback function, void *context) 8878c2ecf20Sopenharmony_ci{ 8888c2ecf20Sopenharmony_ci int ret; 8898c2ecf20Sopenharmony_ci int (*func)(acpi_osd_exec_callback, void *); 8908c2ecf20Sopenharmony_ci struct module *owner; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci if (!acpi_debugger_initialized) 8938c2ecf20Sopenharmony_ci return -ENODEV; 8948c2ecf20Sopenharmony_ci mutex_lock(&acpi_debugger.lock); 8958c2ecf20Sopenharmony_ci if (!acpi_debugger.ops) { 8968c2ecf20Sopenharmony_ci ret = -ENODEV; 8978c2ecf20Sopenharmony_ci goto err_lock; 8988c2ecf20Sopenharmony_ci } 8998c2ecf20Sopenharmony_ci if (!try_module_get(acpi_debugger.owner)) { 9008c2ecf20Sopenharmony_ci ret = -ENODEV; 9018c2ecf20Sopenharmony_ci goto err_lock; 9028c2ecf20Sopenharmony_ci } 9038c2ecf20Sopenharmony_ci func = acpi_debugger.ops->create_thread; 9048c2ecf20Sopenharmony_ci owner = acpi_debugger.owner; 9058c2ecf20Sopenharmony_ci mutex_unlock(&acpi_debugger.lock); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci ret = func(function, context); 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci mutex_lock(&acpi_debugger.lock); 9108c2ecf20Sopenharmony_ci module_put(owner); 9118c2ecf20Sopenharmony_cierr_lock: 9128c2ecf20Sopenharmony_ci mutex_unlock(&acpi_debugger.lock); 9138c2ecf20Sopenharmony_ci return ret; 9148c2ecf20Sopenharmony_ci} 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_cissize_t acpi_debugger_write_log(const char *msg) 9178c2ecf20Sopenharmony_ci{ 9188c2ecf20Sopenharmony_ci ssize_t ret; 9198c2ecf20Sopenharmony_ci ssize_t (*func)(const char *); 9208c2ecf20Sopenharmony_ci struct module *owner; 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_ci if (!acpi_debugger_initialized) 9238c2ecf20Sopenharmony_ci return -ENODEV; 9248c2ecf20Sopenharmony_ci mutex_lock(&acpi_debugger.lock); 9258c2ecf20Sopenharmony_ci if (!acpi_debugger.ops) { 9268c2ecf20Sopenharmony_ci ret = -ENODEV; 9278c2ecf20Sopenharmony_ci goto err_lock; 9288c2ecf20Sopenharmony_ci } 9298c2ecf20Sopenharmony_ci if (!try_module_get(acpi_debugger.owner)) { 9308c2ecf20Sopenharmony_ci ret = -ENODEV; 9318c2ecf20Sopenharmony_ci goto err_lock; 9328c2ecf20Sopenharmony_ci } 9338c2ecf20Sopenharmony_ci func = acpi_debugger.ops->write_log; 9348c2ecf20Sopenharmony_ci owner = acpi_debugger.owner; 9358c2ecf20Sopenharmony_ci mutex_unlock(&acpi_debugger.lock); 9368c2ecf20Sopenharmony_ci 9378c2ecf20Sopenharmony_ci ret = func(msg); 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci mutex_lock(&acpi_debugger.lock); 9408c2ecf20Sopenharmony_ci module_put(owner); 9418c2ecf20Sopenharmony_cierr_lock: 9428c2ecf20Sopenharmony_ci mutex_unlock(&acpi_debugger.lock); 9438c2ecf20Sopenharmony_ci return ret; 9448c2ecf20Sopenharmony_ci} 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_cissize_t acpi_debugger_read_cmd(char *buffer, size_t buffer_length) 9478c2ecf20Sopenharmony_ci{ 9488c2ecf20Sopenharmony_ci ssize_t ret; 9498c2ecf20Sopenharmony_ci ssize_t (*func)(char *, size_t); 9508c2ecf20Sopenharmony_ci struct module *owner; 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci if (!acpi_debugger_initialized) 9538c2ecf20Sopenharmony_ci return -ENODEV; 9548c2ecf20Sopenharmony_ci mutex_lock(&acpi_debugger.lock); 9558c2ecf20Sopenharmony_ci if (!acpi_debugger.ops) { 9568c2ecf20Sopenharmony_ci ret = -ENODEV; 9578c2ecf20Sopenharmony_ci goto err_lock; 9588c2ecf20Sopenharmony_ci } 9598c2ecf20Sopenharmony_ci if (!try_module_get(acpi_debugger.owner)) { 9608c2ecf20Sopenharmony_ci ret = -ENODEV; 9618c2ecf20Sopenharmony_ci goto err_lock; 9628c2ecf20Sopenharmony_ci } 9638c2ecf20Sopenharmony_ci func = acpi_debugger.ops->read_cmd; 9648c2ecf20Sopenharmony_ci owner = acpi_debugger.owner; 9658c2ecf20Sopenharmony_ci mutex_unlock(&acpi_debugger.lock); 9668c2ecf20Sopenharmony_ci 9678c2ecf20Sopenharmony_ci ret = func(buffer, buffer_length); 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci mutex_lock(&acpi_debugger.lock); 9708c2ecf20Sopenharmony_ci module_put(owner); 9718c2ecf20Sopenharmony_cierr_lock: 9728c2ecf20Sopenharmony_ci mutex_unlock(&acpi_debugger.lock); 9738c2ecf20Sopenharmony_ci return ret; 9748c2ecf20Sopenharmony_ci} 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ciint acpi_debugger_wait_command_ready(void) 9778c2ecf20Sopenharmony_ci{ 9788c2ecf20Sopenharmony_ci int ret; 9798c2ecf20Sopenharmony_ci int (*func)(bool, char *, size_t); 9808c2ecf20Sopenharmony_ci struct module *owner; 9818c2ecf20Sopenharmony_ci 9828c2ecf20Sopenharmony_ci if (!acpi_debugger_initialized) 9838c2ecf20Sopenharmony_ci return -ENODEV; 9848c2ecf20Sopenharmony_ci mutex_lock(&acpi_debugger.lock); 9858c2ecf20Sopenharmony_ci if (!acpi_debugger.ops) { 9868c2ecf20Sopenharmony_ci ret = -ENODEV; 9878c2ecf20Sopenharmony_ci goto err_lock; 9888c2ecf20Sopenharmony_ci } 9898c2ecf20Sopenharmony_ci if (!try_module_get(acpi_debugger.owner)) { 9908c2ecf20Sopenharmony_ci ret = -ENODEV; 9918c2ecf20Sopenharmony_ci goto err_lock; 9928c2ecf20Sopenharmony_ci } 9938c2ecf20Sopenharmony_ci func = acpi_debugger.ops->wait_command_ready; 9948c2ecf20Sopenharmony_ci owner = acpi_debugger.owner; 9958c2ecf20Sopenharmony_ci mutex_unlock(&acpi_debugger.lock); 9968c2ecf20Sopenharmony_ci 9978c2ecf20Sopenharmony_ci ret = func(acpi_gbl_method_executing, 9988c2ecf20Sopenharmony_ci acpi_gbl_db_line_buf, ACPI_DB_LINE_BUFFER_SIZE); 9998c2ecf20Sopenharmony_ci 10008c2ecf20Sopenharmony_ci mutex_lock(&acpi_debugger.lock); 10018c2ecf20Sopenharmony_ci module_put(owner); 10028c2ecf20Sopenharmony_cierr_lock: 10038c2ecf20Sopenharmony_ci mutex_unlock(&acpi_debugger.lock); 10048c2ecf20Sopenharmony_ci return ret; 10058c2ecf20Sopenharmony_ci} 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_ciint acpi_debugger_notify_command_complete(void) 10088c2ecf20Sopenharmony_ci{ 10098c2ecf20Sopenharmony_ci int ret; 10108c2ecf20Sopenharmony_ci int (*func)(void); 10118c2ecf20Sopenharmony_ci struct module *owner; 10128c2ecf20Sopenharmony_ci 10138c2ecf20Sopenharmony_ci if (!acpi_debugger_initialized) 10148c2ecf20Sopenharmony_ci return -ENODEV; 10158c2ecf20Sopenharmony_ci mutex_lock(&acpi_debugger.lock); 10168c2ecf20Sopenharmony_ci if (!acpi_debugger.ops) { 10178c2ecf20Sopenharmony_ci ret = -ENODEV; 10188c2ecf20Sopenharmony_ci goto err_lock; 10198c2ecf20Sopenharmony_ci } 10208c2ecf20Sopenharmony_ci if (!try_module_get(acpi_debugger.owner)) { 10218c2ecf20Sopenharmony_ci ret = -ENODEV; 10228c2ecf20Sopenharmony_ci goto err_lock; 10238c2ecf20Sopenharmony_ci } 10248c2ecf20Sopenharmony_ci func = acpi_debugger.ops->notify_command_complete; 10258c2ecf20Sopenharmony_ci owner = acpi_debugger.owner; 10268c2ecf20Sopenharmony_ci mutex_unlock(&acpi_debugger.lock); 10278c2ecf20Sopenharmony_ci 10288c2ecf20Sopenharmony_ci ret = func(); 10298c2ecf20Sopenharmony_ci 10308c2ecf20Sopenharmony_ci mutex_lock(&acpi_debugger.lock); 10318c2ecf20Sopenharmony_ci module_put(owner); 10328c2ecf20Sopenharmony_cierr_lock: 10338c2ecf20Sopenharmony_ci mutex_unlock(&acpi_debugger.lock); 10348c2ecf20Sopenharmony_ci return ret; 10358c2ecf20Sopenharmony_ci} 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_ciint __init acpi_debugger_init(void) 10388c2ecf20Sopenharmony_ci{ 10398c2ecf20Sopenharmony_ci mutex_init(&acpi_debugger.lock); 10408c2ecf20Sopenharmony_ci acpi_debugger_initialized = true; 10418c2ecf20Sopenharmony_ci return 0; 10428c2ecf20Sopenharmony_ci} 10438c2ecf20Sopenharmony_ci#endif 10448c2ecf20Sopenharmony_ci 10458c2ecf20Sopenharmony_ci/******************************************************************************* 10468c2ecf20Sopenharmony_ci * 10478c2ecf20Sopenharmony_ci * FUNCTION: acpi_os_execute 10488c2ecf20Sopenharmony_ci * 10498c2ecf20Sopenharmony_ci * PARAMETERS: Type - Type of the callback 10508c2ecf20Sopenharmony_ci * Function - Function to be executed 10518c2ecf20Sopenharmony_ci * Context - Function parameters 10528c2ecf20Sopenharmony_ci * 10538c2ecf20Sopenharmony_ci * RETURN: Status 10548c2ecf20Sopenharmony_ci * 10558c2ecf20Sopenharmony_ci * DESCRIPTION: Depending on type, either queues function for deferred execution or 10568c2ecf20Sopenharmony_ci * immediately executes function on a separate thread. 10578c2ecf20Sopenharmony_ci * 10588c2ecf20Sopenharmony_ci ******************************************************************************/ 10598c2ecf20Sopenharmony_ci 10608c2ecf20Sopenharmony_ciacpi_status acpi_os_execute(acpi_execute_type type, 10618c2ecf20Sopenharmony_ci acpi_osd_exec_callback function, void *context) 10628c2ecf20Sopenharmony_ci{ 10638c2ecf20Sopenharmony_ci acpi_status status = AE_OK; 10648c2ecf20Sopenharmony_ci struct acpi_os_dpc *dpc; 10658c2ecf20Sopenharmony_ci struct workqueue_struct *queue; 10668c2ecf20Sopenharmony_ci int ret; 10678c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 10688c2ecf20Sopenharmony_ci "Scheduling function [%p(%p)] for deferred execution.\n", 10698c2ecf20Sopenharmony_ci function, context)); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci if (type == OSL_DEBUGGER_MAIN_THREAD) { 10728c2ecf20Sopenharmony_ci ret = acpi_debugger_create_thread(function, context); 10738c2ecf20Sopenharmony_ci if (ret) { 10748c2ecf20Sopenharmony_ci pr_err("Call to kthread_create() failed.\n"); 10758c2ecf20Sopenharmony_ci status = AE_ERROR; 10768c2ecf20Sopenharmony_ci } 10778c2ecf20Sopenharmony_ci goto out_thread; 10788c2ecf20Sopenharmony_ci } 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci /* 10818c2ecf20Sopenharmony_ci * Allocate/initialize DPC structure. Note that this memory will be 10828c2ecf20Sopenharmony_ci * freed by the callee. The kernel handles the work_struct list in a 10838c2ecf20Sopenharmony_ci * way that allows us to also free its memory inside the callee. 10848c2ecf20Sopenharmony_ci * Because we may want to schedule several tasks with different 10858c2ecf20Sopenharmony_ci * parameters we can't use the approach some kernel code uses of 10868c2ecf20Sopenharmony_ci * having a static work_struct. 10878c2ecf20Sopenharmony_ci */ 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci dpc = kzalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC); 10908c2ecf20Sopenharmony_ci if (!dpc) 10918c2ecf20Sopenharmony_ci return AE_NO_MEMORY; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci dpc->function = function; 10948c2ecf20Sopenharmony_ci dpc->context = context; 10958c2ecf20Sopenharmony_ci 10968c2ecf20Sopenharmony_ci /* 10978c2ecf20Sopenharmony_ci * To prevent lockdep from complaining unnecessarily, make sure that 10988c2ecf20Sopenharmony_ci * there is a different static lockdep key for each workqueue by using 10998c2ecf20Sopenharmony_ci * INIT_WORK() for each of them separately. 11008c2ecf20Sopenharmony_ci */ 11018c2ecf20Sopenharmony_ci if (type == OSL_NOTIFY_HANDLER) { 11028c2ecf20Sopenharmony_ci queue = kacpi_notify_wq; 11038c2ecf20Sopenharmony_ci INIT_WORK(&dpc->work, acpi_os_execute_deferred); 11048c2ecf20Sopenharmony_ci } else if (type == OSL_GPE_HANDLER) { 11058c2ecf20Sopenharmony_ci queue = kacpid_wq; 11068c2ecf20Sopenharmony_ci INIT_WORK(&dpc->work, acpi_os_execute_deferred); 11078c2ecf20Sopenharmony_ci } else { 11088c2ecf20Sopenharmony_ci pr_err("Unsupported os_execute type %d.\n", type); 11098c2ecf20Sopenharmony_ci status = AE_ERROR; 11108c2ecf20Sopenharmony_ci } 11118c2ecf20Sopenharmony_ci 11128c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 11138c2ecf20Sopenharmony_ci goto err_workqueue; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci /* 11168c2ecf20Sopenharmony_ci * On some machines, a software-initiated SMI causes corruption unless 11178c2ecf20Sopenharmony_ci * the SMI runs on CPU 0. An SMI can be initiated by any AML, but 11188c2ecf20Sopenharmony_ci * typically it's done in GPE-related methods that are run via 11198c2ecf20Sopenharmony_ci * workqueues, so we can avoid the known corruption cases by always 11208c2ecf20Sopenharmony_ci * queueing on CPU 0. 11218c2ecf20Sopenharmony_ci */ 11228c2ecf20Sopenharmony_ci ret = queue_work_on(0, queue, &dpc->work); 11238c2ecf20Sopenharmony_ci if (!ret) { 11248c2ecf20Sopenharmony_ci printk(KERN_ERR PREFIX 11258c2ecf20Sopenharmony_ci "Call to queue_work() failed.\n"); 11268c2ecf20Sopenharmony_ci status = AE_ERROR; 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_cierr_workqueue: 11298c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 11308c2ecf20Sopenharmony_ci kfree(dpc); 11318c2ecf20Sopenharmony_ciout_thread: 11328c2ecf20Sopenharmony_ci return status; 11338c2ecf20Sopenharmony_ci} 11348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_os_execute); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_civoid acpi_os_wait_events_complete(void) 11378c2ecf20Sopenharmony_ci{ 11388c2ecf20Sopenharmony_ci /* 11398c2ecf20Sopenharmony_ci * Make sure the GPE handler or the fixed event handler is not used 11408c2ecf20Sopenharmony_ci * on another CPU after removal. 11418c2ecf20Sopenharmony_ci */ 11428c2ecf20Sopenharmony_ci if (acpi_sci_irq_valid()) 11438c2ecf20Sopenharmony_ci synchronize_hardirq(acpi_sci_irq); 11448c2ecf20Sopenharmony_ci flush_workqueue(kacpid_wq); 11458c2ecf20Sopenharmony_ci flush_workqueue(kacpi_notify_wq); 11468c2ecf20Sopenharmony_ci} 11478c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_os_wait_events_complete); 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_cistruct acpi_hp_work { 11508c2ecf20Sopenharmony_ci struct work_struct work; 11518c2ecf20Sopenharmony_ci struct acpi_device *adev; 11528c2ecf20Sopenharmony_ci u32 src; 11538c2ecf20Sopenharmony_ci}; 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_cistatic void acpi_hotplug_work_fn(struct work_struct *work) 11568c2ecf20Sopenharmony_ci{ 11578c2ecf20Sopenharmony_ci struct acpi_hp_work *hpw = container_of(work, struct acpi_hp_work, work); 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_ci acpi_os_wait_events_complete(); 11608c2ecf20Sopenharmony_ci acpi_device_hotplug(hpw->adev, hpw->src); 11618c2ecf20Sopenharmony_ci kfree(hpw); 11628c2ecf20Sopenharmony_ci} 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ciacpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src) 11658c2ecf20Sopenharmony_ci{ 11668c2ecf20Sopenharmony_ci struct acpi_hp_work *hpw; 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_EXEC, 11698c2ecf20Sopenharmony_ci "Scheduling hotplug event (%p, %u) for deferred execution.\n", 11708c2ecf20Sopenharmony_ci adev, src)); 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci hpw = kmalloc(sizeof(*hpw), GFP_KERNEL); 11738c2ecf20Sopenharmony_ci if (!hpw) 11748c2ecf20Sopenharmony_ci return AE_NO_MEMORY; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci INIT_WORK(&hpw->work, acpi_hotplug_work_fn); 11778c2ecf20Sopenharmony_ci hpw->adev = adev; 11788c2ecf20Sopenharmony_ci hpw->src = src; 11798c2ecf20Sopenharmony_ci /* 11808c2ecf20Sopenharmony_ci * We can't run hotplug code in kacpid_wq/kacpid_notify_wq etc., because 11818c2ecf20Sopenharmony_ci * the hotplug code may call driver .remove() functions, which may 11828c2ecf20Sopenharmony_ci * invoke flush_scheduled_work()/acpi_os_wait_events_complete() to flush 11838c2ecf20Sopenharmony_ci * these workqueues. 11848c2ecf20Sopenharmony_ci */ 11858c2ecf20Sopenharmony_ci if (!queue_work(kacpi_hotplug_wq, &hpw->work)) { 11868c2ecf20Sopenharmony_ci kfree(hpw); 11878c2ecf20Sopenharmony_ci return AE_ERROR; 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci return AE_OK; 11908c2ecf20Sopenharmony_ci} 11918c2ecf20Sopenharmony_ci 11928c2ecf20Sopenharmony_cibool acpi_queue_hotplug_work(struct work_struct *work) 11938c2ecf20Sopenharmony_ci{ 11948c2ecf20Sopenharmony_ci return queue_work(kacpi_hotplug_wq, work); 11958c2ecf20Sopenharmony_ci} 11968c2ecf20Sopenharmony_ci 11978c2ecf20Sopenharmony_ciacpi_status 11988c2ecf20Sopenharmony_ciacpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle) 11998c2ecf20Sopenharmony_ci{ 12008c2ecf20Sopenharmony_ci struct semaphore *sem = NULL; 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci sem = acpi_os_allocate_zeroed(sizeof(struct semaphore)); 12038c2ecf20Sopenharmony_ci if (!sem) 12048c2ecf20Sopenharmony_ci return AE_NO_MEMORY; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci sema_init(sem, initial_units); 12078c2ecf20Sopenharmony_ci 12088c2ecf20Sopenharmony_ci *handle = (acpi_handle *) sem; 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Creating semaphore[%p|%d].\n", 12118c2ecf20Sopenharmony_ci *handle, initial_units)); 12128c2ecf20Sopenharmony_ci 12138c2ecf20Sopenharmony_ci return AE_OK; 12148c2ecf20Sopenharmony_ci} 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci/* 12178c2ecf20Sopenharmony_ci * TODO: A better way to delete semaphores? Linux doesn't have a 12188c2ecf20Sopenharmony_ci * 'delete_semaphore()' function -- may result in an invalid 12198c2ecf20Sopenharmony_ci * pointer dereference for non-synchronized consumers. Should 12208c2ecf20Sopenharmony_ci * we at least check for blocked threads and signal/cancel them? 12218c2ecf20Sopenharmony_ci */ 12228c2ecf20Sopenharmony_ci 12238c2ecf20Sopenharmony_ciacpi_status acpi_os_delete_semaphore(acpi_handle handle) 12248c2ecf20Sopenharmony_ci{ 12258c2ecf20Sopenharmony_ci struct semaphore *sem = (struct semaphore *)handle; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci if (!sem) 12288c2ecf20Sopenharmony_ci return AE_BAD_PARAMETER; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Deleting semaphore[%p].\n", handle)); 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci BUG_ON(!list_empty(&sem->wait_list)); 12338c2ecf20Sopenharmony_ci kfree(sem); 12348c2ecf20Sopenharmony_ci sem = NULL; 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci return AE_OK; 12378c2ecf20Sopenharmony_ci} 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci/* 12408c2ecf20Sopenharmony_ci * TODO: Support for units > 1? 12418c2ecf20Sopenharmony_ci */ 12428c2ecf20Sopenharmony_ciacpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout) 12438c2ecf20Sopenharmony_ci{ 12448c2ecf20Sopenharmony_ci acpi_status status = AE_OK; 12458c2ecf20Sopenharmony_ci struct semaphore *sem = (struct semaphore *)handle; 12468c2ecf20Sopenharmony_ci long jiffies; 12478c2ecf20Sopenharmony_ci int ret = 0; 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci if (!acpi_os_initialized) 12508c2ecf20Sopenharmony_ci return AE_OK; 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ci if (!sem || (units < 1)) 12538c2ecf20Sopenharmony_ci return AE_BAD_PARAMETER; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci if (units > 1) 12568c2ecf20Sopenharmony_ci return AE_SUPPORT; 12578c2ecf20Sopenharmony_ci 12588c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Waiting for semaphore[%p|%d|%d]\n", 12598c2ecf20Sopenharmony_ci handle, units, timeout)); 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci if (timeout == ACPI_WAIT_FOREVER) 12628c2ecf20Sopenharmony_ci jiffies = MAX_SCHEDULE_TIMEOUT; 12638c2ecf20Sopenharmony_ci else 12648c2ecf20Sopenharmony_ci jiffies = msecs_to_jiffies(timeout); 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci ret = down_timeout(sem, jiffies); 12678c2ecf20Sopenharmony_ci if (ret) 12688c2ecf20Sopenharmony_ci status = AE_TIME; 12698c2ecf20Sopenharmony_ci 12708c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) { 12718c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 12728c2ecf20Sopenharmony_ci "Failed to acquire semaphore[%p|%d|%d], %s", 12738c2ecf20Sopenharmony_ci handle, units, timeout, 12748c2ecf20Sopenharmony_ci acpi_format_exception(status))); 12758c2ecf20Sopenharmony_ci } else { 12768c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, 12778c2ecf20Sopenharmony_ci "Acquired semaphore[%p|%d|%d]", handle, 12788c2ecf20Sopenharmony_ci units, timeout)); 12798c2ecf20Sopenharmony_ci } 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci return status; 12828c2ecf20Sopenharmony_ci} 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ci/* 12858c2ecf20Sopenharmony_ci * TODO: Support for units > 1? 12868c2ecf20Sopenharmony_ci */ 12878c2ecf20Sopenharmony_ciacpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units) 12888c2ecf20Sopenharmony_ci{ 12898c2ecf20Sopenharmony_ci struct semaphore *sem = (struct semaphore *)handle; 12908c2ecf20Sopenharmony_ci 12918c2ecf20Sopenharmony_ci if (!acpi_os_initialized) 12928c2ecf20Sopenharmony_ci return AE_OK; 12938c2ecf20Sopenharmony_ci 12948c2ecf20Sopenharmony_ci if (!sem || (units < 1)) 12958c2ecf20Sopenharmony_ci return AE_BAD_PARAMETER; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci if (units > 1) 12988c2ecf20Sopenharmony_ci return AE_SUPPORT; 12998c2ecf20Sopenharmony_ci 13008c2ecf20Sopenharmony_ci ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Signaling semaphore[%p|%d]\n", handle, 13018c2ecf20Sopenharmony_ci units)); 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci up(sem); 13048c2ecf20Sopenharmony_ci 13058c2ecf20Sopenharmony_ci return AE_OK; 13068c2ecf20Sopenharmony_ci} 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ciacpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read) 13098c2ecf20Sopenharmony_ci{ 13108c2ecf20Sopenharmony_ci#ifdef ENABLE_DEBUGGER 13118c2ecf20Sopenharmony_ci if (acpi_in_debugger) { 13128c2ecf20Sopenharmony_ci u32 chars; 13138c2ecf20Sopenharmony_ci 13148c2ecf20Sopenharmony_ci kdb_read(buffer, buffer_length); 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci /* remove the CR kdb includes */ 13178c2ecf20Sopenharmony_ci chars = strlen(buffer) - 1; 13188c2ecf20Sopenharmony_ci buffer[chars] = '\0'; 13198c2ecf20Sopenharmony_ci } 13208c2ecf20Sopenharmony_ci#else 13218c2ecf20Sopenharmony_ci int ret; 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci ret = acpi_debugger_read_cmd(buffer, buffer_length); 13248c2ecf20Sopenharmony_ci if (ret < 0) 13258c2ecf20Sopenharmony_ci return AE_ERROR; 13268c2ecf20Sopenharmony_ci if (bytes_read) 13278c2ecf20Sopenharmony_ci *bytes_read = ret; 13288c2ecf20Sopenharmony_ci#endif 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci return AE_OK; 13318c2ecf20Sopenharmony_ci} 13328c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_os_get_line); 13338c2ecf20Sopenharmony_ci 13348c2ecf20Sopenharmony_ciacpi_status acpi_os_wait_command_ready(void) 13358c2ecf20Sopenharmony_ci{ 13368c2ecf20Sopenharmony_ci int ret; 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci ret = acpi_debugger_wait_command_ready(); 13398c2ecf20Sopenharmony_ci if (ret < 0) 13408c2ecf20Sopenharmony_ci return AE_ERROR; 13418c2ecf20Sopenharmony_ci return AE_OK; 13428c2ecf20Sopenharmony_ci} 13438c2ecf20Sopenharmony_ci 13448c2ecf20Sopenharmony_ciacpi_status acpi_os_notify_command_complete(void) 13458c2ecf20Sopenharmony_ci{ 13468c2ecf20Sopenharmony_ci int ret; 13478c2ecf20Sopenharmony_ci 13488c2ecf20Sopenharmony_ci ret = acpi_debugger_notify_command_complete(); 13498c2ecf20Sopenharmony_ci if (ret < 0) 13508c2ecf20Sopenharmony_ci return AE_ERROR; 13518c2ecf20Sopenharmony_ci return AE_OK; 13528c2ecf20Sopenharmony_ci} 13538c2ecf20Sopenharmony_ci 13548c2ecf20Sopenharmony_ciacpi_status acpi_os_signal(u32 function, void *info) 13558c2ecf20Sopenharmony_ci{ 13568c2ecf20Sopenharmony_ci switch (function) { 13578c2ecf20Sopenharmony_ci case ACPI_SIGNAL_FATAL: 13588c2ecf20Sopenharmony_ci printk(KERN_ERR PREFIX "Fatal opcode executed\n"); 13598c2ecf20Sopenharmony_ci break; 13608c2ecf20Sopenharmony_ci case ACPI_SIGNAL_BREAKPOINT: 13618c2ecf20Sopenharmony_ci /* 13628c2ecf20Sopenharmony_ci * AML Breakpoint 13638c2ecf20Sopenharmony_ci * ACPI spec. says to treat it as a NOP unless 13648c2ecf20Sopenharmony_ci * you are debugging. So if/when we integrate 13658c2ecf20Sopenharmony_ci * AML debugger into the kernel debugger its 13668c2ecf20Sopenharmony_ci * hook will go here. But until then it is 13678c2ecf20Sopenharmony_ci * not useful to print anything on breakpoints. 13688c2ecf20Sopenharmony_ci */ 13698c2ecf20Sopenharmony_ci break; 13708c2ecf20Sopenharmony_ci default: 13718c2ecf20Sopenharmony_ci break; 13728c2ecf20Sopenharmony_ci } 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci return AE_OK; 13758c2ecf20Sopenharmony_ci} 13768c2ecf20Sopenharmony_ci 13778c2ecf20Sopenharmony_cistatic int __init acpi_os_name_setup(char *str) 13788c2ecf20Sopenharmony_ci{ 13798c2ecf20Sopenharmony_ci char *p = acpi_os_name; 13808c2ecf20Sopenharmony_ci int count = ACPI_MAX_OVERRIDE_LEN - 1; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci if (!str || !*str) 13838c2ecf20Sopenharmony_ci return 0; 13848c2ecf20Sopenharmony_ci 13858c2ecf20Sopenharmony_ci for (; count-- && *str; str++) { 13868c2ecf20Sopenharmony_ci if (isalnum(*str) || *str == ' ' || *str == ':') 13878c2ecf20Sopenharmony_ci *p++ = *str; 13888c2ecf20Sopenharmony_ci else if (*str == '\'' || *str == '"') 13898c2ecf20Sopenharmony_ci continue; 13908c2ecf20Sopenharmony_ci else 13918c2ecf20Sopenharmony_ci break; 13928c2ecf20Sopenharmony_ci } 13938c2ecf20Sopenharmony_ci *p = 0; 13948c2ecf20Sopenharmony_ci 13958c2ecf20Sopenharmony_ci return 1; 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci} 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci__setup("acpi_os_name=", acpi_os_name_setup); 14008c2ecf20Sopenharmony_ci 14018c2ecf20Sopenharmony_ci/* 14028c2ecf20Sopenharmony_ci * Disable the auto-serialization of named objects creation methods. 14038c2ecf20Sopenharmony_ci * 14048c2ecf20Sopenharmony_ci * This feature is enabled by default. It marks the AML control methods 14058c2ecf20Sopenharmony_ci * that contain the opcodes to create named objects as "Serialized". 14068c2ecf20Sopenharmony_ci */ 14078c2ecf20Sopenharmony_cistatic int __init acpi_no_auto_serialize_setup(char *str) 14088c2ecf20Sopenharmony_ci{ 14098c2ecf20Sopenharmony_ci acpi_gbl_auto_serialize_methods = FALSE; 14108c2ecf20Sopenharmony_ci pr_info("ACPI: auto-serialization disabled\n"); 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci return 1; 14138c2ecf20Sopenharmony_ci} 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci__setup("acpi_no_auto_serialize", acpi_no_auto_serialize_setup); 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci/* Check of resource interference between native drivers and ACPI 14188c2ecf20Sopenharmony_ci * OperationRegions (SystemIO and System Memory only). 14198c2ecf20Sopenharmony_ci * IO ports and memory declared in ACPI might be used by the ACPI subsystem 14208c2ecf20Sopenharmony_ci * in arbitrary AML code and can interfere with legacy drivers. 14218c2ecf20Sopenharmony_ci * acpi_enforce_resources= can be set to: 14228c2ecf20Sopenharmony_ci * 14238c2ecf20Sopenharmony_ci * - strict (default) (2) 14248c2ecf20Sopenharmony_ci * -> further driver trying to access the resources will not load 14258c2ecf20Sopenharmony_ci * - lax (1) 14268c2ecf20Sopenharmony_ci * -> further driver trying to access the resources will load, but you 14278c2ecf20Sopenharmony_ci * get a system message that something might go wrong... 14288c2ecf20Sopenharmony_ci * 14298c2ecf20Sopenharmony_ci * - no (0) 14308c2ecf20Sopenharmony_ci * -> ACPI Operation Region resources will not be registered 14318c2ecf20Sopenharmony_ci * 14328c2ecf20Sopenharmony_ci */ 14338c2ecf20Sopenharmony_ci#define ENFORCE_RESOURCES_STRICT 2 14348c2ecf20Sopenharmony_ci#define ENFORCE_RESOURCES_LAX 1 14358c2ecf20Sopenharmony_ci#define ENFORCE_RESOURCES_NO 0 14368c2ecf20Sopenharmony_ci 14378c2ecf20Sopenharmony_cistatic unsigned int acpi_enforce_resources = ENFORCE_RESOURCES_STRICT; 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_cistatic int __init acpi_enforce_resources_setup(char *str) 14408c2ecf20Sopenharmony_ci{ 14418c2ecf20Sopenharmony_ci if (str == NULL || *str == '\0') 14428c2ecf20Sopenharmony_ci return 0; 14438c2ecf20Sopenharmony_ci 14448c2ecf20Sopenharmony_ci if (!strcmp("strict", str)) 14458c2ecf20Sopenharmony_ci acpi_enforce_resources = ENFORCE_RESOURCES_STRICT; 14468c2ecf20Sopenharmony_ci else if (!strcmp("lax", str)) 14478c2ecf20Sopenharmony_ci acpi_enforce_resources = ENFORCE_RESOURCES_LAX; 14488c2ecf20Sopenharmony_ci else if (!strcmp("no", str)) 14498c2ecf20Sopenharmony_ci acpi_enforce_resources = ENFORCE_RESOURCES_NO; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci return 1; 14528c2ecf20Sopenharmony_ci} 14538c2ecf20Sopenharmony_ci 14548c2ecf20Sopenharmony_ci__setup("acpi_enforce_resources=", acpi_enforce_resources_setup); 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci/* Check for resource conflicts between ACPI OperationRegions and native 14578c2ecf20Sopenharmony_ci * drivers */ 14588c2ecf20Sopenharmony_ciint acpi_check_resource_conflict(const struct resource *res) 14598c2ecf20Sopenharmony_ci{ 14608c2ecf20Sopenharmony_ci acpi_adr_space_type space_id; 14618c2ecf20Sopenharmony_ci acpi_size length; 14628c2ecf20Sopenharmony_ci u8 warn = 0; 14638c2ecf20Sopenharmony_ci int clash = 0; 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) 14668c2ecf20Sopenharmony_ci return 0; 14678c2ecf20Sopenharmony_ci if (!(res->flags & IORESOURCE_IO) && !(res->flags & IORESOURCE_MEM)) 14688c2ecf20Sopenharmony_ci return 0; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci if (res->flags & IORESOURCE_IO) 14718c2ecf20Sopenharmony_ci space_id = ACPI_ADR_SPACE_SYSTEM_IO; 14728c2ecf20Sopenharmony_ci else 14738c2ecf20Sopenharmony_ci space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY; 14748c2ecf20Sopenharmony_ci 14758c2ecf20Sopenharmony_ci length = resource_size(res); 14768c2ecf20Sopenharmony_ci if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) 14778c2ecf20Sopenharmony_ci warn = 1; 14788c2ecf20Sopenharmony_ci clash = acpi_check_address_range(space_id, res->start, length, warn); 14798c2ecf20Sopenharmony_ci 14808c2ecf20Sopenharmony_ci if (clash) { 14818c2ecf20Sopenharmony_ci if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) { 14828c2ecf20Sopenharmony_ci if (acpi_enforce_resources == ENFORCE_RESOURCES_LAX) 14838c2ecf20Sopenharmony_ci printk(KERN_NOTICE "ACPI: This conflict may" 14848c2ecf20Sopenharmony_ci " cause random problems and system" 14858c2ecf20Sopenharmony_ci " instability\n"); 14868c2ecf20Sopenharmony_ci printk(KERN_INFO "ACPI: If an ACPI driver is available" 14878c2ecf20Sopenharmony_ci " for this device, you should use it instead of" 14888c2ecf20Sopenharmony_ci " the native driver\n"); 14898c2ecf20Sopenharmony_ci } 14908c2ecf20Sopenharmony_ci if (acpi_enforce_resources == ENFORCE_RESOURCES_STRICT) 14918c2ecf20Sopenharmony_ci return -EBUSY; 14928c2ecf20Sopenharmony_ci } 14938c2ecf20Sopenharmony_ci return 0; 14948c2ecf20Sopenharmony_ci} 14958c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_check_resource_conflict); 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ciint acpi_check_region(resource_size_t start, resource_size_t n, 14988c2ecf20Sopenharmony_ci const char *name) 14998c2ecf20Sopenharmony_ci{ 15008c2ecf20Sopenharmony_ci struct resource res = { 15018c2ecf20Sopenharmony_ci .start = start, 15028c2ecf20Sopenharmony_ci .end = start + n - 1, 15038c2ecf20Sopenharmony_ci .name = name, 15048c2ecf20Sopenharmony_ci .flags = IORESOURCE_IO, 15058c2ecf20Sopenharmony_ci }; 15068c2ecf20Sopenharmony_ci 15078c2ecf20Sopenharmony_ci return acpi_check_resource_conflict(&res); 15088c2ecf20Sopenharmony_ci} 15098c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_check_region); 15108c2ecf20Sopenharmony_ci 15118c2ecf20Sopenharmony_cistatic acpi_status acpi_deactivate_mem_region(acpi_handle handle, u32 level, 15128c2ecf20Sopenharmony_ci void *_res, void **return_value) 15138c2ecf20Sopenharmony_ci{ 15148c2ecf20Sopenharmony_ci struct acpi_mem_space_context **mem_ctx; 15158c2ecf20Sopenharmony_ci union acpi_operand_object *handler_obj; 15168c2ecf20Sopenharmony_ci union acpi_operand_object *region_obj2; 15178c2ecf20Sopenharmony_ci union acpi_operand_object *region_obj; 15188c2ecf20Sopenharmony_ci struct resource *res = _res; 15198c2ecf20Sopenharmony_ci acpi_status status; 15208c2ecf20Sopenharmony_ci 15218c2ecf20Sopenharmony_ci region_obj = acpi_ns_get_attached_object(handle); 15228c2ecf20Sopenharmony_ci if (!region_obj) 15238c2ecf20Sopenharmony_ci return AE_OK; 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_ci handler_obj = region_obj->region.handler; 15268c2ecf20Sopenharmony_ci if (!handler_obj) 15278c2ecf20Sopenharmony_ci return AE_OK; 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci if (region_obj->region.space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) 15308c2ecf20Sopenharmony_ci return AE_OK; 15318c2ecf20Sopenharmony_ci 15328c2ecf20Sopenharmony_ci if (!(region_obj->region.flags & AOPOBJ_SETUP_COMPLETE)) 15338c2ecf20Sopenharmony_ci return AE_OK; 15348c2ecf20Sopenharmony_ci 15358c2ecf20Sopenharmony_ci region_obj2 = acpi_ns_get_secondary_object(region_obj); 15368c2ecf20Sopenharmony_ci if (!region_obj2) 15378c2ecf20Sopenharmony_ci return AE_OK; 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci mem_ctx = (void *)®ion_obj2->extra.region_context; 15408c2ecf20Sopenharmony_ci 15418c2ecf20Sopenharmony_ci if (!(mem_ctx[0]->address >= res->start && 15428c2ecf20Sopenharmony_ci mem_ctx[0]->address < res->end)) 15438c2ecf20Sopenharmony_ci return AE_OK; 15448c2ecf20Sopenharmony_ci 15458c2ecf20Sopenharmony_ci status = handler_obj->address_space.setup(region_obj, 15468c2ecf20Sopenharmony_ci ACPI_REGION_DEACTIVATE, 15478c2ecf20Sopenharmony_ci NULL, (void **)mem_ctx); 15488c2ecf20Sopenharmony_ci if (ACPI_SUCCESS(status)) 15498c2ecf20Sopenharmony_ci region_obj->region.flags &= ~(AOPOBJ_SETUP_COMPLETE); 15508c2ecf20Sopenharmony_ci 15518c2ecf20Sopenharmony_ci return status; 15528c2ecf20Sopenharmony_ci} 15538c2ecf20Sopenharmony_ci 15548c2ecf20Sopenharmony_ci/** 15558c2ecf20Sopenharmony_ci * acpi_release_memory - Release any mappings done to a memory region 15568c2ecf20Sopenharmony_ci * @handle: Handle to namespace node 15578c2ecf20Sopenharmony_ci * @res: Memory resource 15588c2ecf20Sopenharmony_ci * @level: A level that terminates the search 15598c2ecf20Sopenharmony_ci * 15608c2ecf20Sopenharmony_ci * Walks through @handle and unmaps all SystemMemory Operation Regions that 15618c2ecf20Sopenharmony_ci * overlap with @res and that have already been activated (mapped). 15628c2ecf20Sopenharmony_ci * 15638c2ecf20Sopenharmony_ci * This is a helper that allows drivers to place special requirements on memory 15648c2ecf20Sopenharmony_ci * region that may overlap with operation regions, primarily allowing them to 15658c2ecf20Sopenharmony_ci * safely map the region as non-cached memory. 15668c2ecf20Sopenharmony_ci * 15678c2ecf20Sopenharmony_ci * The unmapped Operation Regions will be automatically remapped next time they 15688c2ecf20Sopenharmony_ci * are called, so the drivers do not need to do anything else. 15698c2ecf20Sopenharmony_ci */ 15708c2ecf20Sopenharmony_ciacpi_status acpi_release_memory(acpi_handle handle, struct resource *res, 15718c2ecf20Sopenharmony_ci u32 level) 15728c2ecf20Sopenharmony_ci{ 15738c2ecf20Sopenharmony_ci acpi_status status; 15748c2ecf20Sopenharmony_ci 15758c2ecf20Sopenharmony_ci if (!(res->flags & IORESOURCE_MEM)) 15768c2ecf20Sopenharmony_ci return AE_TYPE; 15778c2ecf20Sopenharmony_ci 15788c2ecf20Sopenharmony_ci status = acpi_walk_namespace(ACPI_TYPE_REGION, handle, level, 15798c2ecf20Sopenharmony_ci acpi_deactivate_mem_region, NULL, 15808c2ecf20Sopenharmony_ci res, NULL); 15818c2ecf20Sopenharmony_ci if (ACPI_FAILURE(status)) 15828c2ecf20Sopenharmony_ci return status; 15838c2ecf20Sopenharmony_ci 15848c2ecf20Sopenharmony_ci /* 15858c2ecf20Sopenharmony_ci * Wait for all of the mappings queued up for removal by 15868c2ecf20Sopenharmony_ci * acpi_deactivate_mem_region() to actually go away. 15878c2ecf20Sopenharmony_ci */ 15888c2ecf20Sopenharmony_ci synchronize_rcu(); 15898c2ecf20Sopenharmony_ci rcu_barrier(); 15908c2ecf20Sopenharmony_ci flush_scheduled_work(); 15918c2ecf20Sopenharmony_ci 15928c2ecf20Sopenharmony_ci return AE_OK; 15938c2ecf20Sopenharmony_ci} 15948c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(acpi_release_memory); 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci/* 15978c2ecf20Sopenharmony_ci * Let drivers know whether the resource checks are effective 15988c2ecf20Sopenharmony_ci */ 15998c2ecf20Sopenharmony_ciint acpi_resources_are_enforced(void) 16008c2ecf20Sopenharmony_ci{ 16018c2ecf20Sopenharmony_ci return acpi_enforce_resources == ENFORCE_RESOURCES_STRICT; 16028c2ecf20Sopenharmony_ci} 16038c2ecf20Sopenharmony_ciEXPORT_SYMBOL(acpi_resources_are_enforced); 16048c2ecf20Sopenharmony_ci 16058c2ecf20Sopenharmony_ci/* 16068c2ecf20Sopenharmony_ci * Deallocate the memory for a spinlock. 16078c2ecf20Sopenharmony_ci */ 16088c2ecf20Sopenharmony_civoid acpi_os_delete_lock(acpi_spinlock handle) 16098c2ecf20Sopenharmony_ci{ 16108c2ecf20Sopenharmony_ci ACPI_FREE(handle); 16118c2ecf20Sopenharmony_ci} 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci/* 16148c2ecf20Sopenharmony_ci * Acquire a spinlock. 16158c2ecf20Sopenharmony_ci * 16168c2ecf20Sopenharmony_ci * handle is a pointer to the spinlock_t. 16178c2ecf20Sopenharmony_ci */ 16188c2ecf20Sopenharmony_ci 16198c2ecf20Sopenharmony_ciacpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp) 16208c2ecf20Sopenharmony_ci __acquires(lockp) 16218c2ecf20Sopenharmony_ci{ 16228c2ecf20Sopenharmony_ci acpi_cpu_flags flags; 16238c2ecf20Sopenharmony_ci spin_lock_irqsave(lockp, flags); 16248c2ecf20Sopenharmony_ci return flags; 16258c2ecf20Sopenharmony_ci} 16268c2ecf20Sopenharmony_ci 16278c2ecf20Sopenharmony_ci/* 16288c2ecf20Sopenharmony_ci * Release a spinlock. See above. 16298c2ecf20Sopenharmony_ci */ 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_civoid acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags flags) 16328c2ecf20Sopenharmony_ci __releases(lockp) 16338c2ecf20Sopenharmony_ci{ 16348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(lockp, flags); 16358c2ecf20Sopenharmony_ci} 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci#ifndef ACPI_USE_LOCAL_CACHE 16388c2ecf20Sopenharmony_ci 16398c2ecf20Sopenharmony_ci/******************************************************************************* 16408c2ecf20Sopenharmony_ci * 16418c2ecf20Sopenharmony_ci * FUNCTION: acpi_os_create_cache 16428c2ecf20Sopenharmony_ci * 16438c2ecf20Sopenharmony_ci * PARAMETERS: name - Ascii name for the cache 16448c2ecf20Sopenharmony_ci * size - Size of each cached object 16458c2ecf20Sopenharmony_ci * depth - Maximum depth of the cache (in objects) <ignored> 16468c2ecf20Sopenharmony_ci * cache - Where the new cache object is returned 16478c2ecf20Sopenharmony_ci * 16488c2ecf20Sopenharmony_ci * RETURN: status 16498c2ecf20Sopenharmony_ci * 16508c2ecf20Sopenharmony_ci * DESCRIPTION: Create a cache object 16518c2ecf20Sopenharmony_ci * 16528c2ecf20Sopenharmony_ci ******************************************************************************/ 16538c2ecf20Sopenharmony_ci 16548c2ecf20Sopenharmony_ciacpi_status 16558c2ecf20Sopenharmony_ciacpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache) 16568c2ecf20Sopenharmony_ci{ 16578c2ecf20Sopenharmony_ci *cache = kmem_cache_create(name, size, 0, 0, NULL); 16588c2ecf20Sopenharmony_ci if (*cache == NULL) 16598c2ecf20Sopenharmony_ci return AE_ERROR; 16608c2ecf20Sopenharmony_ci else 16618c2ecf20Sopenharmony_ci return AE_OK; 16628c2ecf20Sopenharmony_ci} 16638c2ecf20Sopenharmony_ci 16648c2ecf20Sopenharmony_ci/******************************************************************************* 16658c2ecf20Sopenharmony_ci * 16668c2ecf20Sopenharmony_ci * FUNCTION: acpi_os_purge_cache 16678c2ecf20Sopenharmony_ci * 16688c2ecf20Sopenharmony_ci * PARAMETERS: Cache - Handle to cache object 16698c2ecf20Sopenharmony_ci * 16708c2ecf20Sopenharmony_ci * RETURN: Status 16718c2ecf20Sopenharmony_ci * 16728c2ecf20Sopenharmony_ci * DESCRIPTION: Free all objects within the requested cache. 16738c2ecf20Sopenharmony_ci * 16748c2ecf20Sopenharmony_ci ******************************************************************************/ 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ciacpi_status acpi_os_purge_cache(acpi_cache_t * cache) 16778c2ecf20Sopenharmony_ci{ 16788c2ecf20Sopenharmony_ci kmem_cache_shrink(cache); 16798c2ecf20Sopenharmony_ci return (AE_OK); 16808c2ecf20Sopenharmony_ci} 16818c2ecf20Sopenharmony_ci 16828c2ecf20Sopenharmony_ci/******************************************************************************* 16838c2ecf20Sopenharmony_ci * 16848c2ecf20Sopenharmony_ci * FUNCTION: acpi_os_delete_cache 16858c2ecf20Sopenharmony_ci * 16868c2ecf20Sopenharmony_ci * PARAMETERS: Cache - Handle to cache object 16878c2ecf20Sopenharmony_ci * 16888c2ecf20Sopenharmony_ci * RETURN: Status 16898c2ecf20Sopenharmony_ci * 16908c2ecf20Sopenharmony_ci * DESCRIPTION: Free all objects within the requested cache and delete the 16918c2ecf20Sopenharmony_ci * cache object. 16928c2ecf20Sopenharmony_ci * 16938c2ecf20Sopenharmony_ci ******************************************************************************/ 16948c2ecf20Sopenharmony_ci 16958c2ecf20Sopenharmony_ciacpi_status acpi_os_delete_cache(acpi_cache_t * cache) 16968c2ecf20Sopenharmony_ci{ 16978c2ecf20Sopenharmony_ci kmem_cache_destroy(cache); 16988c2ecf20Sopenharmony_ci return (AE_OK); 16998c2ecf20Sopenharmony_ci} 17008c2ecf20Sopenharmony_ci 17018c2ecf20Sopenharmony_ci/******************************************************************************* 17028c2ecf20Sopenharmony_ci * 17038c2ecf20Sopenharmony_ci * FUNCTION: acpi_os_release_object 17048c2ecf20Sopenharmony_ci * 17058c2ecf20Sopenharmony_ci * PARAMETERS: Cache - Handle to cache object 17068c2ecf20Sopenharmony_ci * Object - The object to be released 17078c2ecf20Sopenharmony_ci * 17088c2ecf20Sopenharmony_ci * RETURN: None 17098c2ecf20Sopenharmony_ci * 17108c2ecf20Sopenharmony_ci * DESCRIPTION: Release an object to the specified cache. If cache is full, 17118c2ecf20Sopenharmony_ci * the object is deleted. 17128c2ecf20Sopenharmony_ci * 17138c2ecf20Sopenharmony_ci ******************************************************************************/ 17148c2ecf20Sopenharmony_ci 17158c2ecf20Sopenharmony_ciacpi_status acpi_os_release_object(acpi_cache_t * cache, void *object) 17168c2ecf20Sopenharmony_ci{ 17178c2ecf20Sopenharmony_ci kmem_cache_free(cache, object); 17188c2ecf20Sopenharmony_ci return (AE_OK); 17198c2ecf20Sopenharmony_ci} 17208c2ecf20Sopenharmony_ci#endif 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_cistatic int __init acpi_no_static_ssdt_setup(char *s) 17238c2ecf20Sopenharmony_ci{ 17248c2ecf20Sopenharmony_ci acpi_gbl_disable_ssdt_table_install = TRUE; 17258c2ecf20Sopenharmony_ci pr_info("ACPI: static SSDT installation disabled\n"); 17268c2ecf20Sopenharmony_ci 17278c2ecf20Sopenharmony_ci return 0; 17288c2ecf20Sopenharmony_ci} 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ciearly_param("acpi_no_static_ssdt", acpi_no_static_ssdt_setup); 17318c2ecf20Sopenharmony_ci 17328c2ecf20Sopenharmony_cistatic int __init acpi_disable_return_repair(char *s) 17338c2ecf20Sopenharmony_ci{ 17348c2ecf20Sopenharmony_ci printk(KERN_NOTICE PREFIX 17358c2ecf20Sopenharmony_ci "ACPI: Predefined validation mechanism disabled\n"); 17368c2ecf20Sopenharmony_ci acpi_gbl_disable_auto_repair = TRUE; 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci return 1; 17398c2ecf20Sopenharmony_ci} 17408c2ecf20Sopenharmony_ci 17418c2ecf20Sopenharmony_ci__setup("acpica_no_return_repair", acpi_disable_return_repair); 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ciacpi_status __init acpi_os_initialize(void) 17448c2ecf20Sopenharmony_ci{ 17458c2ecf20Sopenharmony_ci acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1a_event_block); 17468c2ecf20Sopenharmony_ci acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1b_event_block); 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ci acpi_gbl_xgpe0_block_logical_address = 17498c2ecf20Sopenharmony_ci (unsigned long)acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe0_block); 17508c2ecf20Sopenharmony_ci acpi_gbl_xgpe1_block_logical_address = 17518c2ecf20Sopenharmony_ci (unsigned long)acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe1_block); 17528c2ecf20Sopenharmony_ci 17538c2ecf20Sopenharmony_ci if (acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) { 17548c2ecf20Sopenharmony_ci /* 17558c2ecf20Sopenharmony_ci * Use acpi_os_map_generic_address to pre-map the reset 17568c2ecf20Sopenharmony_ci * register if it's in system memory. 17578c2ecf20Sopenharmony_ci */ 17588c2ecf20Sopenharmony_ci void *rv; 17598c2ecf20Sopenharmony_ci 17608c2ecf20Sopenharmony_ci rv = acpi_os_map_generic_address(&acpi_gbl_FADT.reset_register); 17618c2ecf20Sopenharmony_ci pr_debug(PREFIX "%s: map reset_reg %s\n", __func__, 17628c2ecf20Sopenharmony_ci rv ? "successful" : "failed"); 17638c2ecf20Sopenharmony_ci } 17648c2ecf20Sopenharmony_ci acpi_os_initialized = true; 17658c2ecf20Sopenharmony_ci 17668c2ecf20Sopenharmony_ci return AE_OK; 17678c2ecf20Sopenharmony_ci} 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ciacpi_status __init acpi_os_initialize1(void) 17708c2ecf20Sopenharmony_ci{ 17718c2ecf20Sopenharmony_ci kacpid_wq = alloc_workqueue("kacpid", 0, 1); 17728c2ecf20Sopenharmony_ci kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1); 17738c2ecf20Sopenharmony_ci kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0); 17748c2ecf20Sopenharmony_ci BUG_ON(!kacpid_wq); 17758c2ecf20Sopenharmony_ci BUG_ON(!kacpi_notify_wq); 17768c2ecf20Sopenharmony_ci BUG_ON(!kacpi_hotplug_wq); 17778c2ecf20Sopenharmony_ci acpi_osi_init(); 17788c2ecf20Sopenharmony_ci return AE_OK; 17798c2ecf20Sopenharmony_ci} 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ciacpi_status acpi_os_terminate(void) 17828c2ecf20Sopenharmony_ci{ 17838c2ecf20Sopenharmony_ci if (acpi_irq_handler) { 17848c2ecf20Sopenharmony_ci acpi_os_remove_interrupt_handler(acpi_gbl_FADT.sci_interrupt, 17858c2ecf20Sopenharmony_ci acpi_irq_handler); 17868c2ecf20Sopenharmony_ci } 17878c2ecf20Sopenharmony_ci 17888c2ecf20Sopenharmony_ci acpi_os_unmap_generic_address(&acpi_gbl_FADT.xgpe1_block); 17898c2ecf20Sopenharmony_ci acpi_os_unmap_generic_address(&acpi_gbl_FADT.xgpe0_block); 17908c2ecf20Sopenharmony_ci acpi_gbl_xgpe0_block_logical_address = 0UL; 17918c2ecf20Sopenharmony_ci acpi_gbl_xgpe1_block_logical_address = 0UL; 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1b_event_block); 17948c2ecf20Sopenharmony_ci acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1a_event_block); 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci if (acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) 17978c2ecf20Sopenharmony_ci acpi_os_unmap_generic_address(&acpi_gbl_FADT.reset_register); 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ci destroy_workqueue(kacpid_wq); 18008c2ecf20Sopenharmony_ci destroy_workqueue(kacpi_notify_wq); 18018c2ecf20Sopenharmony_ci destroy_workqueue(kacpi_hotplug_wq); 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci return AE_OK; 18048c2ecf20Sopenharmony_ci} 18058c2ecf20Sopenharmony_ci 18068c2ecf20Sopenharmony_ciacpi_status acpi_os_prepare_sleep(u8 sleep_state, u32 pm1a_control, 18078c2ecf20Sopenharmony_ci u32 pm1b_control) 18088c2ecf20Sopenharmony_ci{ 18098c2ecf20Sopenharmony_ci int rc = 0; 18108c2ecf20Sopenharmony_ci if (__acpi_os_prepare_sleep) 18118c2ecf20Sopenharmony_ci rc = __acpi_os_prepare_sleep(sleep_state, 18128c2ecf20Sopenharmony_ci pm1a_control, pm1b_control); 18138c2ecf20Sopenharmony_ci if (rc < 0) 18148c2ecf20Sopenharmony_ci return AE_ERROR; 18158c2ecf20Sopenharmony_ci else if (rc > 0) 18168c2ecf20Sopenharmony_ci return AE_CTRL_TERMINATE; 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci return AE_OK; 18198c2ecf20Sopenharmony_ci} 18208c2ecf20Sopenharmony_ci 18218c2ecf20Sopenharmony_civoid acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state, 18228c2ecf20Sopenharmony_ci u32 pm1a_ctrl, u32 pm1b_ctrl)) 18238c2ecf20Sopenharmony_ci{ 18248c2ecf20Sopenharmony_ci __acpi_os_prepare_sleep = func; 18258c2ecf20Sopenharmony_ci} 18268c2ecf20Sopenharmony_ci 18278c2ecf20Sopenharmony_ci#if (ACPI_REDUCED_HARDWARE) 18288c2ecf20Sopenharmony_ciacpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a, 18298c2ecf20Sopenharmony_ci u32 val_b) 18308c2ecf20Sopenharmony_ci{ 18318c2ecf20Sopenharmony_ci int rc = 0; 18328c2ecf20Sopenharmony_ci if (__acpi_os_prepare_extended_sleep) 18338c2ecf20Sopenharmony_ci rc = __acpi_os_prepare_extended_sleep(sleep_state, 18348c2ecf20Sopenharmony_ci val_a, val_b); 18358c2ecf20Sopenharmony_ci if (rc < 0) 18368c2ecf20Sopenharmony_ci return AE_ERROR; 18378c2ecf20Sopenharmony_ci else if (rc > 0) 18388c2ecf20Sopenharmony_ci return AE_CTRL_TERMINATE; 18398c2ecf20Sopenharmony_ci 18408c2ecf20Sopenharmony_ci return AE_OK; 18418c2ecf20Sopenharmony_ci} 18428c2ecf20Sopenharmony_ci#else 18438c2ecf20Sopenharmony_ciacpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a, 18448c2ecf20Sopenharmony_ci u32 val_b) 18458c2ecf20Sopenharmony_ci{ 18468c2ecf20Sopenharmony_ci return AE_OK; 18478c2ecf20Sopenharmony_ci} 18488c2ecf20Sopenharmony_ci#endif 18498c2ecf20Sopenharmony_ci 18508c2ecf20Sopenharmony_civoid acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state, 18518c2ecf20Sopenharmony_ci u32 val_a, u32 val_b)) 18528c2ecf20Sopenharmony_ci{ 18538c2ecf20Sopenharmony_ci __acpi_os_prepare_extended_sleep = func; 18548c2ecf20Sopenharmony_ci} 18558c2ecf20Sopenharmony_ci 18568c2ecf20Sopenharmony_ciacpi_status acpi_os_enter_sleep(u8 sleep_state, 18578c2ecf20Sopenharmony_ci u32 reg_a_value, u32 reg_b_value) 18588c2ecf20Sopenharmony_ci{ 18598c2ecf20Sopenharmony_ci acpi_status status; 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_ci if (acpi_gbl_reduced_hardware) 18628c2ecf20Sopenharmony_ci status = acpi_os_prepare_extended_sleep(sleep_state, 18638c2ecf20Sopenharmony_ci reg_a_value, 18648c2ecf20Sopenharmony_ci reg_b_value); 18658c2ecf20Sopenharmony_ci else 18668c2ecf20Sopenharmony_ci status = acpi_os_prepare_sleep(sleep_state, 18678c2ecf20Sopenharmony_ci reg_a_value, reg_b_value); 18688c2ecf20Sopenharmony_ci return status; 18698c2ecf20Sopenharmony_ci} 1870