diff options
Diffstat (limited to 'drivers/acpi/osl.c')
| -rw-r--r-- | drivers/acpi/osl.c | 1091 | 
1 files changed, 715 insertions, 376 deletions
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c index 966feddf6b1..bad25b070fe 100644 --- a/drivers/acpi/osl.c +++ b/drivers/acpi/osl.c @@ -31,6 +31,7 @@  #include <linux/kernel.h>  #include <linux/slab.h>  #include <linux/mm.h> +#include <linux/highmem.h>  #include <linux/pci.h>  #include <linux/interrupt.h>  #include <linux/kmod.h> @@ -47,18 +48,15 @@  #include <asm/io.h>  #include <asm/uaccess.h> -#include <acpi/acpi.h> -#include <acpi/acpi_bus.h> -#include <acpi/processor.h> +#include "internal.h"  #define _COMPONENT		ACPI_OS_SERVICES  ACPI_MODULE_NAME("osl"); -#define PREFIX		"ACPI: " +  struct acpi_os_dpc {  	acpi_osd_exec_callback function;  	void *context;  	struct work_struct work; -	int wait;  };  #ifdef CONFIG_ACPI_CUSTOM_DSDT @@ -75,26 +73,17 @@ EXPORT_SYMBOL(acpi_in_debugger);  extern char line_buf[80];  #endif				/*ENABLE_DEBUGGER */ -static unsigned int acpi_irq_irq; +static int (*__acpi_os_prepare_sleep)(u8 sleep_state, u32 pm1a_ctrl, +				      u32 pm1b_ctrl); +static int (*__acpi_os_prepare_extended_sleep)(u8 sleep_state, u32 val_a, +				      u32 val_b); +  static acpi_osd_handler acpi_irq_handler;  static void *acpi_irq_context;  static struct workqueue_struct *kacpid_wq;  static struct workqueue_struct *kacpi_notify_wq;  static struct workqueue_struct *kacpi_hotplug_wq; -struct acpi_res_list { -	resource_size_t start; -	resource_size_t end; -	acpi_adr_space_type resource_type; /* IO port, System memory, ...*/ -	char name[5];   /* only can have a length of 4 chars, make use of this -			   one instead of res->name, no need to kalloc then */ -	struct list_head resource_list; -	int count; -}; - -static LIST_HEAD(resource_list_head); -static DEFINE_SPINLOCK(acpi_res_lock); -  /*   * This list of permanent mappings is for memory that may be accessed from   * interrupt context, where we can't do the ioremap(). @@ -104,14 +93,11 @@ struct acpi_ioremap {  	void __iomem *virt;  	acpi_physical_address phys;  	acpi_size size; -	struct kref ref; +	unsigned long refcount;  };  static LIST_HEAD(acpi_ioremaps); -static DEFINE_SPINLOCK(acpi_ioremap_lock); - -#define	OSI_STRING_LENGTH_MAX 64	/* arbitrary */ -static char osi_setup_string[OSI_STRING_LENGTH_MAX]; +static DEFINE_MUTEX(acpi_ioremap_lock);  static void __init acpi_osi_setup_late(void); @@ -152,14 +138,14 @@ static struct osi_linux {  	unsigned int	enable:1;  	unsigned int	dmi:1;  	unsigned int	cmdline:1; -	unsigned int	known:1; -} osi_linux = { 0, 0, 0, 0}; +	unsigned int	default_disabling:1; +} osi_linux = {0, 0, 0, 0};  static u32 acpi_osi_handler(acpi_string interface, u32 supported)  {  	if (!strcmp("Linux", interface)) { -		printk(KERN_NOTICE FW_BUG PREFIX +		printk_once(KERN_NOTICE FW_BUG PREFIX  			"BIOS _OSI(Linux) query %s%s\n",  			osi_linux.enable ? "honored" : "ignored",  			osi_linux.cmdline ? " via cmdline" : @@ -169,17 +155,21 @@ static u32 acpi_osi_handler(acpi_string interface, u32 supported)  	return supported;  } -static void __init acpi_request_region (struct acpi_generic_address *addr, +static void __init acpi_request_region (struct acpi_generic_address *gas,  	unsigned int length, char *desc)  { -	if (!addr->address || !length) +	u64 addr; + +	/* Handle possible alignment issues */ +	memcpy(&addr, &gas->address, sizeof(addr)); +	if (!addr || !length)  		return;  	/* Resources are never freed */ -	if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_IO) -		request_region(addr->address, length, desc); -	else if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) -		request_mem_region(addr->address, length, desc); +	if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO) +		request_region(addr, length, desc); +	else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY) +		request_mem_region(addr, length, desc);  }  static int __init acpi_reserve_resources(void) @@ -241,9 +231,25 @@ void acpi_os_vprintf(const char *fmt, va_list args)  #endif  } +#ifdef CONFIG_KEXEC +static unsigned long acpi_rsdp; +static int __init setup_acpi_rsdp(char *arg) +{ +	if (kstrtoul(arg, 16, &acpi_rsdp)) +		return -EINVAL; +	return 0; +} +early_param("acpi_rsdp", setup_acpi_rsdp); +#endif +  acpi_physical_address __init acpi_os_get_root_pointer(void)  { -	if (efi_enabled) { +#ifdef CONFIG_KEXEC +	if (acpi_rsdp) +		return acpi_rsdp; +#endif + +	if (efi_enabled(EFI_CONFIG_TABLES)) {  		if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)  			return efi.acpi20;  		else if (efi.acpi != EFI_INVALID_TABLE_ADDR) @@ -288,6 +294,22 @@ acpi_map_vaddr_lookup(acpi_physical_address phys, unsigned int size)  	return NULL;  } +void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size) +{ +	struct acpi_ioremap *map; +	void __iomem *virt = NULL; + +	mutex_lock(&acpi_ioremap_lock); +	map = acpi_map_lookup(phys, size); +	if (map) { +		virt = map->virt + (phys - map->phys); +		map->refcount++; +	} +	mutex_unlock(&acpi_ioremap_lock); +	return virt; +} +EXPORT_SYMBOL_GPL(acpi_os_get_iomem); +  /* Must be called with 'acpi_ioremap_lock' or RCU read lock held. */  static struct acpi_ioremap *  acpi_map_lookup_virt(void __iomem *virt, acpi_size size) @@ -302,13 +324,44 @@ acpi_map_lookup_virt(void __iomem *virt, acpi_size size)  	return NULL;  } +#ifndef CONFIG_IA64 +#define should_use_kmap(pfn)   page_is_ram(pfn) +#else +/* ioremap will take care of cache attributes */ +#define should_use_kmap(pfn)   0 +#endif + +static void __iomem *acpi_map(acpi_physical_address pg_off, unsigned long pg_sz) +{ +	unsigned long pfn; + +	pfn = pg_off >> PAGE_SHIFT; +	if (should_use_kmap(pfn)) { +		if (pg_sz > PAGE_SIZE) +			return NULL; +		return (void __iomem __force *)kmap(pfn_to_page(pfn)); +	} else +		return acpi_os_ioremap(pg_off, pg_sz); +} + +static void acpi_unmap(acpi_physical_address pg_off, void __iomem *vaddr) +{ +	unsigned long pfn; + +	pfn = pg_off >> PAGE_SHIFT; +	if (should_use_kmap(pfn)) +		kunmap(pfn_to_page(pfn)); +	else +		iounmap(vaddr); +} +  void __iomem *__init_refok -acpi_os_map_memory(acpi_physical_address phys, acpi_size size) +acpi_os_map_iomem(acpi_physical_address phys, acpi_size size)  { -	struct acpi_ioremap *map, *tmp_map; -	unsigned long flags, pg_sz; +	struct acpi_ioremap *map;  	void __iomem *virt; -	phys_addr_t pg_off; +	acpi_physical_address pg_off; +	acpi_size pg_sz;  	if (phys > ULONG_MAX) {  		printk(KERN_ERR PREFIX "Cannot map memory that high\n"); @@ -318,14 +371,25 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size)  	if (!acpi_gbl_permanent_mmap)  		return __acpi_map_table((unsigned long)phys, size); +	mutex_lock(&acpi_ioremap_lock); +	/* Check if there's a suitable mapping already. */ +	map = acpi_map_lookup(phys, size); +	if (map) { +		map->refcount++; +		goto out; +	} +  	map = kzalloc(sizeof(*map), GFP_KERNEL); -	if (!map) +	if (!map) { +		mutex_unlock(&acpi_ioremap_lock);  		return NULL; +	}  	pg_off = round_down(phys, PAGE_SIZE);  	pg_sz = round_up(phys + size, PAGE_SIZE) - pg_off; -	virt = ioremap(pg_off, pg_sz); +	virt = acpi_map(pg_off, pg_sz);  	if (!virt) { +		mutex_unlock(&acpi_ioremap_lock);  		kfree(map);  		return NULL;  	} @@ -334,62 +398,64 @@ acpi_os_map_memory(acpi_physical_address phys, acpi_size size)  	map->virt = virt;  	map->phys = pg_off;  	map->size = pg_sz; -	kref_init(&map->ref); - -	spin_lock_irqsave(&acpi_ioremap_lock, flags); -	/* Check if page has already been mapped. */ -	tmp_map = acpi_map_lookup(phys, size); -	if (tmp_map) { -		kref_get(&tmp_map->ref); -		spin_unlock_irqrestore(&acpi_ioremap_lock, flags); -		iounmap(map->virt); -		kfree(map); -		return tmp_map->virt + (phys - tmp_map->phys); -	} +	map->refcount = 1; +  	list_add_tail_rcu(&map->list, &acpi_ioremaps); -	spin_unlock_irqrestore(&acpi_ioremap_lock, flags); +out: +	mutex_unlock(&acpi_ioremap_lock);  	return map->virt + (phys - map->phys);  } +EXPORT_SYMBOL_GPL(acpi_os_map_iomem); + +void *__init_refok +acpi_os_map_memory(acpi_physical_address phys, acpi_size size) +{ +	return (void *)acpi_os_map_iomem(phys, size); +}  EXPORT_SYMBOL_GPL(acpi_os_map_memory); -static void acpi_kref_del_iomap(struct kref *ref) +static void acpi_os_drop_map_ref(struct acpi_ioremap *map)  { -	struct acpi_ioremap *map; +	if (!--map->refcount) +		list_del_rcu(&map->list); +} -	map = container_of(ref, struct acpi_ioremap, ref); -	list_del_rcu(&map->list); +static void acpi_os_map_cleanup(struct acpi_ioremap *map) +{ +	if (!map->refcount) { +		synchronize_rcu(); +		acpi_unmap(map->phys, map->virt); +		kfree(map); +	}  } -void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size) +void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size)  {  	struct acpi_ioremap *map; -	unsigned long flags; -	int del;  	if (!acpi_gbl_permanent_mmap) {  		__acpi_unmap_table(virt, size);  		return;  	} -	spin_lock_irqsave(&acpi_ioremap_lock, flags); +	mutex_lock(&acpi_ioremap_lock);  	map = acpi_map_lookup_virt(virt, size);  	if (!map) { -		spin_unlock_irqrestore(&acpi_ioremap_lock, flags); -		printk(KERN_ERR PREFIX "%s: bad address %p\n", __func__, virt); -		dump_stack(); +		mutex_unlock(&acpi_ioremap_lock); +		WARN(true, PREFIX "%s: bad address %p\n", __func__, virt);  		return;  	} +	acpi_os_drop_map_ref(map); +	mutex_unlock(&acpi_ioremap_lock); -	del = kref_put(&map->ref, acpi_kref_del_iomap); -	spin_unlock_irqrestore(&acpi_ioremap_lock, flags); - -	if (!del) -		return; +	acpi_os_map_cleanup(map); +} +EXPORT_SYMBOL_GPL(acpi_os_unmap_iomem); -	synchronize_rcu(); -	iounmap(map->virt); -	kfree(map); +void __ref acpi_os_unmap_memory(void *virt, acpi_size size) +{ +	return acpi_os_unmap_iomem((void __iomem *)virt, size);  }  EXPORT_SYMBOL_GPL(acpi_os_unmap_memory); @@ -399,43 +465,52 @@ void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size)  		__acpi_unmap_table(virt, size);  } -int acpi_os_map_generic_address(struct acpi_generic_address *addr) +int acpi_os_map_generic_address(struct acpi_generic_address *gas)  { +	u64 addr;  	void __iomem *virt; -	if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) +	if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)  		return 0; -	if (!addr->address || !addr->bit_width) +	/* Handle possible alignment issues */ +	memcpy(&addr, &gas->address, sizeof(addr)); +	if (!addr || !gas->bit_width)  		return -EINVAL; -	virt = acpi_os_map_memory(addr->address, addr->bit_width / 8); +	virt = acpi_os_map_iomem(addr, gas->bit_width / 8);  	if (!virt)  		return -EIO;  	return 0;  } -EXPORT_SYMBOL_GPL(acpi_os_map_generic_address); +EXPORT_SYMBOL(acpi_os_map_generic_address); -void acpi_os_unmap_generic_address(struct acpi_generic_address *addr) +void acpi_os_unmap_generic_address(struct acpi_generic_address *gas)  { -	void __iomem *virt; -	unsigned long flags; -	acpi_size size = addr->bit_width / 8; +	u64 addr; +	struct acpi_ioremap *map; -	if (addr->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) +	if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)  		return; -	if (!addr->address || !addr->bit_width) +	/* Handle possible alignment issues */ +	memcpy(&addr, &gas->address, sizeof(addr)); +	if (!addr || !gas->bit_width)  		return; -	spin_lock_irqsave(&acpi_ioremap_lock, flags); -	virt = acpi_map_vaddr_lookup(addr->address, size); -	spin_unlock_irqrestore(&acpi_ioremap_lock, flags); +	mutex_lock(&acpi_ioremap_lock); +	map = acpi_map_lookup(addr, gas->bit_width / 8); +	if (!map) { +		mutex_unlock(&acpi_ioremap_lock); +		return; +	} +	acpi_os_drop_map_ref(map); +	mutex_unlock(&acpi_ioremap_lock); -	acpi_os_unmap_memory(virt, size); +	acpi_os_map_cleanup(map);  } -EXPORT_SYMBOL_GPL(acpi_os_unmap_generic_address); +EXPORT_SYMBOL(acpi_os_unmap_generic_address);  #ifdef ACPI_FUTURE_USAGE  acpi_status @@ -471,6 +546,161 @@ acpi_os_predefined_override(const struct acpi_predefined_names *init_val,  	return AE_OK;  } +#ifdef CONFIG_ACPI_INITRD_TABLE_OVERRIDE +#include <linux/earlycpio.h> +#include <linux/memblock.h> + +static u64 acpi_tables_addr; +static int all_tables_size; + +/* Copied from acpica/tbutils.c:acpi_tb_checksum() */ +static u8 __init acpi_table_checksum(u8 *buffer, u32 length) +{ +	u8 sum = 0; +	u8 *end = buffer + length; + +	while (buffer < end) +		sum = (u8) (sum + *(buffer++)); +	return sum; +} + +/* All but ACPI_SIG_RSDP and ACPI_SIG_FACS: */ +static const char * const table_sigs[] = { +	ACPI_SIG_BERT, ACPI_SIG_CPEP, ACPI_SIG_ECDT, ACPI_SIG_EINJ, +	ACPI_SIG_ERST, ACPI_SIG_HEST, ACPI_SIG_MADT, ACPI_SIG_MSCT, +	ACPI_SIG_SBST, ACPI_SIG_SLIT, ACPI_SIG_SRAT, ACPI_SIG_ASF, +	ACPI_SIG_BOOT, ACPI_SIG_DBGP, ACPI_SIG_DMAR, ACPI_SIG_HPET, +	ACPI_SIG_IBFT, ACPI_SIG_IVRS, ACPI_SIG_MCFG, ACPI_SIG_MCHI, +	ACPI_SIG_SLIC, ACPI_SIG_SPCR, ACPI_SIG_SPMI, ACPI_SIG_TCPA, +	ACPI_SIG_UEFI, ACPI_SIG_WAET, ACPI_SIG_WDAT, ACPI_SIG_WDDT, +	ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT, ACPI_SIG_PSDT, +	ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT, NULL }; + +#define ACPI_HEADER_SIZE sizeof(struct acpi_table_header) + +#define ACPI_OVERRIDE_TABLES 64 +static struct cpio_data __initdata acpi_initrd_files[ACPI_OVERRIDE_TABLES]; + +#define MAP_CHUNK_SIZE   (NR_FIX_BTMAPS << PAGE_SHIFT) + +void __init acpi_initrd_override(void *data, size_t size) +{ +	int sig, no, table_nr = 0, total_offset = 0; +	long offset = 0; +	struct acpi_table_header *table; +	char cpio_path[32] = "kernel/firmware/acpi/"; +	struct cpio_data file; + +	if (data == NULL || size == 0) +		return; + +	for (no = 0; no < ACPI_OVERRIDE_TABLES; no++) { +		file = find_cpio_data(cpio_path, data, size, &offset); +		if (!file.data) +			break; + +		data += offset; +		size -= offset; + +		if (file.size < sizeof(struct acpi_table_header)) { +			pr_err("ACPI OVERRIDE: Table smaller than ACPI header [%s%s]\n", +				cpio_path, file.name); +			continue; +		} + +		table = file.data; + +		for (sig = 0; table_sigs[sig]; sig++) +			if (!memcmp(table->signature, table_sigs[sig], 4)) +				break; + +		if (!table_sigs[sig]) { +			pr_err("ACPI OVERRIDE: Unknown signature [%s%s]\n", +				cpio_path, file.name); +			continue; +		} +		if (file.size != table->length) { +			pr_err("ACPI OVERRIDE: File length does not match table length [%s%s]\n", +				cpio_path, file.name); +			continue; +		} +		if (acpi_table_checksum(file.data, table->length)) { +			pr_err("ACPI OVERRIDE: Bad table checksum [%s%s]\n", +				cpio_path, file.name); +			continue; +		} + +		pr_info("%4.4s ACPI table found in initrd [%s%s][0x%x]\n", +			table->signature, cpio_path, file.name, table->length); + +		all_tables_size += table->length; +		acpi_initrd_files[table_nr].data = file.data; +		acpi_initrd_files[table_nr].size = file.size; +		table_nr++; +	} +	if (table_nr == 0) +		return; + +	acpi_tables_addr = +		memblock_find_in_range(0, max_low_pfn_mapped << PAGE_SHIFT, +				       all_tables_size, PAGE_SIZE); +	if (!acpi_tables_addr) { +		WARN_ON(1); +		return; +	} +	/* +	 * Only calling e820_add_reserve does not work and the +	 * tables are invalid (memory got used) later. +	 * memblock_reserve works as expected and the tables won't get modified. +	 * But it's not enough on X86 because ioremap will +	 * complain later (used by acpi_os_map_memory) that the pages +	 * that should get mapped are not marked "reserved". +	 * Both memblock_reserve and e820_add_region (via arch_reserve_mem_area) +	 * works fine. +	 */ +	memblock_reserve(acpi_tables_addr, all_tables_size); +	arch_reserve_mem_area(acpi_tables_addr, all_tables_size); + +	/* +	 * early_ioremap only can remap 256k one time. If we map all +	 * tables one time, we will hit the limit. Need to map chunks +	 * one by one during copying the same as that in relocate_initrd(). +	 */ +	for (no = 0; no < table_nr; no++) { +		unsigned char *src_p = acpi_initrd_files[no].data; +		phys_addr_t size = acpi_initrd_files[no].size; +		phys_addr_t dest_addr = acpi_tables_addr + total_offset; +		phys_addr_t slop, clen; +		char *dest_p; + +		total_offset += size; + +		while (size) { +			slop = dest_addr & ~PAGE_MASK; +			clen = size; +			if (clen > MAP_CHUNK_SIZE - slop) +				clen = MAP_CHUNK_SIZE - slop; +			dest_p = early_ioremap(dest_addr & PAGE_MASK, +						 clen + slop); +			memcpy(dest_p + slop, src_p, clen); +			early_iounmap(dest_p, clen + slop); +			src_p += clen; +			dest_addr += clen; +			size -= clen; +		} +	} +} +#endif /* CONFIG_ACPI_INITRD_TABLE_OVERRIDE */ + +static void acpi_table_taint(struct acpi_table_header *table) +{ +	pr_warn(PREFIX +		"Override [%4.4s-%8.8s], this is unsafe: tainting kernel\n", +		table->signature, table->oem_table_id); +	add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE); +} + +  acpi_status  acpi_os_table_override(struct acpi_table_header * existing_table,  		       struct acpi_table_header ** new_table) @@ -484,16 +714,74 @@ acpi_os_table_override(struct acpi_table_header * existing_table,  	if (strncmp(existing_table->signature, "DSDT", 4) == 0)  		*new_table = (struct acpi_table_header *)AmlCode;  #endif -	if (*new_table != NULL) { -		printk(KERN_WARNING PREFIX "Override [%4.4s-%8.8s], " -			   "this is unsafe: tainting kernel\n", -		       existing_table->signature, -		       existing_table->oem_table_id); -		add_taint(TAINT_OVERRIDDEN_ACPI_TABLE); -	} +	if (*new_table != NULL) +		acpi_table_taint(existing_table);  	return AE_OK;  } +acpi_status +acpi_os_physical_table_override(struct acpi_table_header *existing_table, +				acpi_physical_address *address, +				u32 *table_length) +{ +#ifndef CONFIG_ACPI_INITRD_TABLE_OVERRIDE +	*table_length = 0; +	*address = 0; +	return AE_OK; +#else +	int table_offset = 0; +	struct acpi_table_header *table; + +	*table_length = 0; +	*address = 0; + +	if (!acpi_tables_addr) +		return AE_OK; + +	do { +		if (table_offset + ACPI_HEADER_SIZE > all_tables_size) { +			WARN_ON(1); +			return AE_OK; +		} + +		table = acpi_os_map_memory(acpi_tables_addr + table_offset, +					   ACPI_HEADER_SIZE); + +		if (table_offset + table->length > all_tables_size) { +			acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); +			WARN_ON(1); +			return AE_OK; +		} + +		table_offset += table->length; + +		if (memcmp(existing_table->signature, table->signature, 4)) { +			acpi_os_unmap_memory(table, +				     ACPI_HEADER_SIZE); +			continue; +		} + +		/* Only override tables with matching oem id */ +		if (memcmp(table->oem_table_id, existing_table->oem_table_id, +			   ACPI_OEM_TABLE_ID_SIZE)) { +			acpi_os_unmap_memory(table, +				     ACPI_HEADER_SIZE); +			continue; +		} + +		table_offset -= table->length; +		*table_length = table->length; +		acpi_os_unmap_memory(table, ACPI_HEADER_SIZE); +		*address = acpi_tables_addr + table_offset; +		break; +	} while (table_offset + ACPI_HEADER_SIZE < all_tables_size); + +	if (*address != 0) +		acpi_table_taint(existing_table); +	return AE_OK; +#endif +} +  static irqreturn_t acpi_irq(int irq, void *dev_id)  {  	u32 handled; @@ -518,11 +806,15 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,  	acpi_irq_stats_init();  	/* -	 * Ignore the GSI from the core, and use the value in our copy of the -	 * FADT. It may not be the same if an interrupt source override exists -	 * for the SCI. +	 * ACPI interrupts different from the SCI in our copy of the FADT are +	 * not supported.  	 */ -	gsi = acpi_gbl_FADT.sci_interrupt; +	if (gsi != acpi_gbl_FADT.sci_interrupt) +		return AE_BAD_PARAMETER; + +	if (acpi_irq_handler) +		return AE_ALREADY_ACQUIRED; +  	if (acpi_gsi_to_irq(gsi, &irq) < 0) {  		printk(KERN_ERR PREFIX "SCI (ACPI GSI %d) not registered\n",  		       gsi); @@ -531,22 +823,22 @@ acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,  	acpi_irq_handler = handler;  	acpi_irq_context = context; -	if (request_irq(irq, acpi_irq, IRQF_SHARED, "acpi", acpi_irq)) { +	if (request_irq(irq, acpi_irq, IRQF_SHARED | IRQF_NO_SUSPEND, "acpi", acpi_irq)) {  		printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq); +		acpi_irq_handler = NULL;  		return AE_NOT_ACQUIRED;  	} -	acpi_irq_irq = irq;  	return AE_OK;  }  acpi_status acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler)  { -	if (irq) { -		free_irq(irq, acpi_irq); -		acpi_irq_handler = NULL; -		acpi_irq_irq = 0; -	} +	if (irq != acpi_gbl_FADT.sci_interrupt) +		return AE_BAD_PARAMETER; + +	free_irq(irq, acpi_irq); +	acpi_irq_handler = NULL;  	return AE_OK;  } @@ -557,7 +849,7 @@ acpi_status acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler)  void acpi_os_sleep(u64 ms)  { -	schedule_timeout_interruptible(msecs_to_jiffies(ms)); +	msleep(ms);  }  void acpi_os_stall(u32 us) @@ -580,19 +872,9 @@ void acpi_os_stall(u32 us)   */  u64 acpi_os_get_timer(void)  { -	static u64 t; - -#ifdef	CONFIG_HPET -	/* TBD: use HPET if available */ -#endif - -#ifdef	CONFIG_X86_PM_TIMER -	/* TBD: default to PM timer if HPET was not available */ -#endif -	if (!t) -		printk(KERN_ERR PREFIX "acpi_os_get_timer() TBD\n"); - -	return ++t; +	u64 time_ns = ktime_to_ns(ktime_get()); +	do_div(time_ns, 100); +	return time_ns;  }  acpi_status acpi_os_read_port(acpi_io_address port, u32 * value, u32 width) @@ -635,20 +917,39 @@ acpi_status acpi_os_write_port(acpi_io_address port, u32 value, u32 width)  EXPORT_SYMBOL(acpi_os_write_port); +#ifdef readq +static inline u64 read64(const volatile void __iomem *addr) +{ +	return readq(addr); +} +#else +static inline u64 read64(const volatile void __iomem *addr) +{ +	u64 l, h; +	l = readl(addr); +	h = readl(addr+4); +	return l | (h << 32); +} +#endif +  acpi_status -acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width) +acpi_os_read_memory(acpi_physical_address phys_addr, u64 *value, u32 width)  { -	u32 dummy;  	void __iomem *virt_addr; -	int size = width / 8, unmap = 0; +	unsigned int size = width / 8; +	bool unmap = false; +	u64 dummy;  	rcu_read_lock();  	virt_addr = acpi_map_vaddr_lookup(phys_addr, size); -	rcu_read_unlock();  	if (!virt_addr) { -		virt_addr = ioremap(phys_addr, size); -		unmap = 1; +		rcu_read_unlock(); +		virt_addr = acpi_os_ioremap(phys_addr, size); +		if (!virt_addr) +			return AE_BAD_ADDRESS; +		unmap = true;  	} +  	if (!value)  		value = &dummy; @@ -662,28 +963,49 @@ acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)  	case 32:  		*(u32 *) value = readl(virt_addr);  		break; +	case 64: +		*(u64 *) value = read64(virt_addr); +		break;  	default:  		BUG();  	}  	if (unmap)  		iounmap(virt_addr); +	else +		rcu_read_unlock();  	return AE_OK;  } +#ifdef writeq +static inline void write64(u64 val, volatile void __iomem *addr) +{ +	writeq(val, addr); +} +#else +static inline void write64(u64 val, volatile void __iomem *addr) +{ +	writel(val, addr); +	writel(val>>32, addr+4); +} +#endif +  acpi_status -acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width) +acpi_os_write_memory(acpi_physical_address phys_addr, u64 value, u32 width)  {  	void __iomem *virt_addr; -	int size = width / 8, unmap = 0; +	unsigned int size = width / 8; +	bool unmap = false;  	rcu_read_lock();  	virt_addr = acpi_map_vaddr_lookup(phys_addr, size); -	rcu_read_unlock();  	if (!virt_addr) { -		virt_addr = ioremap(phys_addr, size); -		unmap = 1; +		rcu_read_unlock(); +		virt_addr = acpi_os_ioremap(phys_addr, size); +		if (!virt_addr) +			return AE_BAD_ADDRESS; +		unmap = true;  	}  	switch (width) { @@ -696,12 +1018,17 @@ acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)  	case 32:  		writel(value, virt_addr);  		break; +	case 64: +		write64(value, virt_addr); +		break;  	default:  		BUG();  	}  	if (unmap)  		iounmap(virt_addr); +	else +		rcu_read_unlock();  	return AE_OK;  } @@ -769,9 +1096,6 @@ static void acpi_os_execute_deferred(struct work_struct *work)  {  	struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work); -	if (dpc->wait) -		acpi_os_wait_events_complete(NULL); -  	dpc->function(dpc->context);  	kfree(dpc);  } @@ -791,8 +1115,8 @@ static void acpi_os_execute_deferred(struct work_struct *work)   *   ******************************************************************************/ -static acpi_status __acpi_os_execute(acpi_execute_type type, -	acpi_osd_exec_callback function, void *context, int hp) +acpi_status acpi_os_execute(acpi_execute_type type, +			    acpi_osd_exec_callback function, void *context)  {  	acpi_status status = AE_OK;  	struct acpi_os_dpc *dpc; @@ -811,7 +1135,7 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,  	 * having a static work_struct.  	 */ -	dpc = kmalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC); +	dpc = kzalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC);  	if (!dpc)  		return AE_NO_MEMORY; @@ -819,21 +1143,17 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,  	dpc->context = context;  	/* -	 * We can't run hotplug code in keventd_wq/kacpid_wq/kacpid_notify_wq -	 * because the hotplug code may call driver .remove() functions, -	 * which invoke flush_scheduled_work/acpi_os_wait_events_complete -	 * to flush these workqueues. +	 * To prevent lockdep from complaining unnecessarily, make sure that +	 * there is a different static lockdep key for each workqueue by using +	 * INIT_WORK() for each of them separately.  	 */ -	queue = hp ? kacpi_hotplug_wq : -		(type == OSL_NOTIFY_HANDLER ? kacpi_notify_wq : kacpid_wq); -	dpc->wait = hp ? 1 : 0; - -	if (queue == kacpi_hotplug_wq) +	if (type == OSL_NOTIFY_HANDLER) { +		queue = kacpi_notify_wq;  		INIT_WORK(&dpc->work, acpi_os_execute_deferred); -	else if (queue == kacpi_notify_wq) -		INIT_WORK(&dpc->work, acpi_os_execute_deferred); -	else +	} else { +		queue = kacpid_wq;  		INIT_WORK(&dpc->work, acpi_os_execute_deferred); +	}  	/*  	 * On some machines, a software-initiated SMI causes corruption unless @@ -852,34 +1172,60 @@ static acpi_status __acpi_os_execute(acpi_execute_type type,  	}  	return status;  } +EXPORT_SYMBOL(acpi_os_execute); -acpi_status acpi_os_execute(acpi_execute_type type, -			    acpi_osd_exec_callback function, void *context) +void acpi_os_wait_events_complete(void)  { -	return __acpi_os_execute(type, function, context, 0); +	flush_workqueue(kacpid_wq); +	flush_workqueue(kacpi_notify_wq);  } -EXPORT_SYMBOL(acpi_os_execute); -acpi_status acpi_os_hotplug_execute(acpi_osd_exec_callback function, -	void *context) +struct acpi_hp_work { +	struct work_struct work; +	struct acpi_device *adev; +	u32 src; +}; + +static void acpi_hotplug_work_fn(struct work_struct *work)  { -	return __acpi_os_execute(0, function, context, 1); +	struct acpi_hp_work *hpw = container_of(work, struct acpi_hp_work, work); + +	acpi_os_wait_events_complete(); +	acpi_device_hotplug(hpw->adev, hpw->src); +	kfree(hpw);  } -void acpi_os_wait_events_complete(void *context) +acpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src)  { -	flush_workqueue(kacpid_wq); -	flush_workqueue(kacpi_notify_wq); -} +	struct acpi_hp_work *hpw; -EXPORT_SYMBOL(acpi_os_wait_events_complete); +	ACPI_DEBUG_PRINT((ACPI_DB_EXEC, +		  "Scheduling hotplug event (%p, %u) for deferred execution.\n", +		  adev, src)); -/* - * Deallocate the memory for a spinlock. - */ -void acpi_os_delete_lock(acpi_spinlock handle) +	hpw = kmalloc(sizeof(*hpw), GFP_KERNEL); +	if (!hpw) +		return AE_NO_MEMORY; + +	INIT_WORK(&hpw->work, acpi_hotplug_work_fn); +	hpw->adev = adev; +	hpw->src = src; +	/* +	 * We can't run hotplug code in kacpid_wq/kacpid_notify_wq etc., because +	 * the hotplug code may call driver .remove() functions, which may +	 * invoke flush_scheduled_work()/acpi_os_wait_events_complete() to flush +	 * these workqueues. +	 */ +	if (!queue_work(kacpi_hotplug_wq, &hpw->work)) { +		kfree(hpw); +		return AE_ERROR; +	} +	return AE_OK; +} + +bool acpi_queue_hotplug_work(struct work_struct *work)  { -	return; +	return queue_work(kacpi_hotplug_wq, work);  }  acpi_status @@ -887,10 +1233,9 @@ acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle)  {  	struct semaphore *sem = NULL; -	sem = acpi_os_allocate(sizeof(struct semaphore)); +	sem = acpi_os_allocate_zeroed(sizeof(struct semaphore));  	if (!sem)  		return AE_NO_MEMORY; -	memset(sem, 0, sizeof(struct semaphore));  	sema_init(sem, initial_units); @@ -948,7 +1293,7 @@ acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout)  		jiffies = MAX_SCHEDULE_TIMEOUT;  	else  		jiffies = msecs_to_jiffies(timeout); -	 +  	ret = down_timeout(sem, jiffies);  	if (ret)  		status = AE_TIME; @@ -1039,7 +1384,7 @@ static int __init acpi_os_name_setup(char *str)  	if (!str || !*str)  		return 0; -	for (; count-- && str && *str; str++) { +	for (; count-- && *str; str++) {  		if (isalnum(*str) || *str == ' ' || *str == ':')  			*p++ = *str;  		else if (*str == '\'' || *str == '"') @@ -1055,13 +1400,70 @@ static int __init acpi_os_name_setup(char *str)  __setup("acpi_os_name=", acpi_os_name_setup); +#define	OSI_STRING_LENGTH_MAX 64	/* arbitrary */ +#define	OSI_STRING_ENTRIES_MAX 16	/* arbitrary */ + +struct osi_setup_entry { +	char string[OSI_STRING_LENGTH_MAX]; +	bool enable; +}; + +static struct osi_setup_entry +		osi_setup_entries[OSI_STRING_ENTRIES_MAX] __initdata = { +	{"Module Device", true}, +	{"Processor Device", true}, +	{"3.0 _SCP Extensions", true}, +	{"Processor Aggregator Device", true}, +}; + +void __init acpi_osi_setup(char *str) +{ +	struct osi_setup_entry *osi; +	bool enable = true; +	int i; + +	if (!acpi_gbl_create_osi_method) +		return; + +	if (str == NULL || *str == '\0') { +		printk(KERN_INFO PREFIX "_OSI method disabled\n"); +		acpi_gbl_create_osi_method = FALSE; +		return; +	} + +	if (*str == '!') { +		str++; +		if (*str == '\0') { +			osi_linux.default_disabling = 1; +			return; +		} else if (*str == '*') { +			acpi_update_interfaces(ACPI_DISABLE_ALL_STRINGS); +			for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) { +				osi = &osi_setup_entries[i]; +				osi->enable = false; +			} +			return; +		} +		enable = false; +	} + +	for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) { +		osi = &osi_setup_entries[i]; +		if (!strcmp(osi->string, str)) { +			osi->enable = enable; +			break; +		} else if (osi->string[0] == '\0') { +			osi->enable = enable; +			strncpy(osi->string, str, OSI_STRING_LENGTH_MAX); +			break; +		} +	} +} +  static void __init set_osi_linux(unsigned int enable)  { -	if (osi_linux.enable != enable) { +	if (osi_linux.enable != enable)  		osi_linux.enable = enable; -		printk(KERN_NOTICE PREFIX "%sed _OSI(Linux)\n", -			enable ? "Add": "Delet"); -	}  	if (osi_linux.enable)  		acpi_osi_setup("Linux"); @@ -1073,7 +1475,8 @@ static void __init set_osi_linux(unsigned int enable)  static void __init acpi_cmdline_osi_linux(unsigned int enable)  { -	osi_linux.cmdline = 1;	/* cmdline set the default */ +	osi_linux.cmdline = 1;	/* cmdline set the default and override DMI */ +	osi_linux.dmi = 0;  	set_osi_linux(enable);  	return; @@ -1081,15 +1484,12 @@ static void __init acpi_cmdline_osi_linux(unsigned int enable)  void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d)  { -	osi_linux.dmi = 1;	/* DMI knows that this box asks OSI(Linux) */ -  	printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);  	if (enable == -1)  		return; -	osi_linux.known = 1;	/* DMI knows which OSI(Linux) default needed */ - +	osi_linux.dmi = 1;	/* DMI knows that this box asks OSI(Linux) */  	set_osi_linux(enable);  	return; @@ -1104,49 +1504,67 @@ void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d)   */  static void __init acpi_osi_setup_late(void)  { -	char *str = osi_setup_string; +	struct osi_setup_entry *osi; +	char *str; +	int i; +	acpi_status status; -	if (*str == '\0') -		return; +	if (osi_linux.default_disabling) { +		status = acpi_update_interfaces(ACPI_DISABLE_ALL_VENDOR_STRINGS); -	if (!strcmp("!Linux", str)) { -		acpi_cmdline_osi_linux(0);	/* !enable */ -	} else if (*str == '!') { -		if (acpi_remove_interface(++str) == AE_OK) -			printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str); -	} else if (!strcmp("Linux", str)) { -		acpi_cmdline_osi_linux(1);	/* enable */ -	} else { -		if (acpi_install_interface(str) == AE_OK) -			printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str); +		if (ACPI_SUCCESS(status)) +			printk(KERN_INFO PREFIX "Disabled all _OSI OS vendors\n"); +	} + +	for (i = 0; i < OSI_STRING_ENTRIES_MAX; i++) { +		osi = &osi_setup_entries[i]; +		str = osi->string; + +		if (*str == '\0') +			break; +		if (osi->enable) { +			status = acpi_install_interface(str); + +			if (ACPI_SUCCESS(status)) +				printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str); +		} else { +			status = acpi_remove_interface(str); + +			if (ACPI_SUCCESS(status)) +				printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str); +		}  	}  } -int __init acpi_osi_setup(char *str) +static int __init osi_setup(char *str)  { -	if (str == NULL || *str == '\0') { -		printk(KERN_INFO PREFIX "_OSI method disabled\n"); -		acpi_gbl_create_osi_method = FALSE; -	} else { -		strncpy(osi_setup_string, str, OSI_STRING_LENGTH_MAX); -	} +	if (str && !strcmp("Linux", str)) +		acpi_cmdline_osi_linux(1); +	else if (str && !strcmp("!Linux", str)) +		acpi_cmdline_osi_linux(0); +	else +		acpi_osi_setup(str);  	return 1;  } -__setup("acpi_osi=", acpi_osi_setup); +__setup("acpi_osi=", osi_setup); -/* enable serialization to combat AE_ALREADY_EXISTS errors */ -static int __init acpi_serialize_setup(char *str) +/* + * Disable the auto-serialization of named objects creation methods. + * + * This feature is enabled by default.  It marks the AML control methods + * that contain the opcodes to create named objects as "Serialized". + */ +static int __init acpi_no_auto_serialize_setup(char *str)  { -	printk(KERN_INFO PREFIX "serialize enabled\n"); - -	acpi_gbl_all_methods_serialized = TRUE; +	acpi_gbl_auto_serialize_methods = FALSE; +	pr_info("ACPI: auto-serialization disabled\n");  	return 1;  } -__setup("acpi_serialize", acpi_serialize_setup); +__setup("acpi_no_auto_serialize", acpi_no_auto_serialize_setup);  /* Check of resource interference between native drivers and ACPI   * OperationRegions (SystemIO and System Memory only). @@ -1191,8 +1609,9 @@ __setup("acpi_enforce_resources=", acpi_enforce_resources_setup);   * drivers */  int acpi_check_resource_conflict(const struct resource *res)  { -	struct acpi_res_list *res_list_elem; -	int ioport; +	acpi_adr_space_type space_id; +	acpi_size length; +	u8 warn = 0;  	int clash = 0;  	if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) @@ -1200,32 +1619,18 @@ int acpi_check_resource_conflict(const struct resource *res)  	if (!(res->flags & IORESOURCE_IO) && !(res->flags & IORESOURCE_MEM))  		return 0; -	ioport = res->flags & IORESOURCE_IO; - -	spin_lock(&acpi_res_lock); -	list_for_each_entry(res_list_elem, &resource_list_head, -			    resource_list) { -		if (ioport && (res_list_elem->resource_type -			       != ACPI_ADR_SPACE_SYSTEM_IO)) -			continue; -		if (!ioport && (res_list_elem->resource_type -				!= ACPI_ADR_SPACE_SYSTEM_MEMORY)) -			continue; +	if (res->flags & IORESOURCE_IO) +		space_id = ACPI_ADR_SPACE_SYSTEM_IO; +	else +		space_id = ACPI_ADR_SPACE_SYSTEM_MEMORY; -		if (res->end < res_list_elem->start -		    || res_list_elem->end < res->start) -			continue; -		clash = 1; -		break; -	} -	spin_unlock(&acpi_res_lock); +	length = resource_size(res); +	if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) +		warn = 1; +	clash = acpi_check_address_range(space_id, res->start, length, warn);  	if (clash) {  		if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) { -			printk(KERN_WARNING "ACPI: resource %s %pR" -			       " conflicts with ACPI region %s %pR\n", -			       res->name, res, res_list_elem->name, -			       res_list_elem);  			if (acpi_enforce_resources == ENFORCE_RESOURCES_LAX)  				printk(KERN_NOTICE "ACPI: This conflict may"  				       " cause random problems and system" @@ -1265,6 +1670,14 @@ int acpi_resources_are_enforced(void)  EXPORT_SYMBOL(acpi_resources_are_enforced);  /* + * Deallocate the memory for a spinlock. + */ +void acpi_os_delete_lock(acpi_spinlock handle) +{ +	ACPI_FREE(handle); +} + +/*   * Acquire a spinlock.   *   * handle is a pointer to the spinlock_t. @@ -1369,156 +1782,28 @@ acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)  	kmem_cache_free(cache, object);  	return (AE_OK);  } +#endif -static inline int acpi_res_list_add(struct acpi_res_list *res) +static int __init acpi_no_static_ssdt_setup(char *s)  { -	struct acpi_res_list *res_list_elem; - -	list_for_each_entry(res_list_elem, &resource_list_head, -			    resource_list) { +	acpi_gbl_disable_ssdt_table_install = TRUE; +	pr_info("ACPI: static SSDT installation disabled\n"); -		if (res->resource_type == res_list_elem->resource_type && -		    res->start == res_list_elem->start && -		    res->end == res_list_elem->end) { - -			/* -			 * The Region(addr,len) already exist in the list, -			 * just increase the count -			 */ - -			res_list_elem->count++; -			return 0; -		} -	} - -	res->count = 1; -	list_add(&res->resource_list, &resource_list_head); -	return 1; +	return 0;  } -static inline void acpi_res_list_del(struct acpi_res_list *res) -{ -	struct acpi_res_list *res_list_elem; - -	list_for_each_entry(res_list_elem, &resource_list_head, -			    resource_list) { - -		if (res->resource_type == res_list_elem->resource_type && -		    res->start == res_list_elem->start && -		    res->end == res_list_elem->end) { +early_param("acpi_no_static_ssdt", acpi_no_static_ssdt_setup); -			/* -			 * If the res count is decreased to 0, -			 * remove and free it -			 */ - -			if (--res_list_elem->count == 0) { -				list_del(&res_list_elem->resource_list); -				kfree(res_list_elem); -			} -			return; -		} -	} -} +static int __init acpi_disable_return_repair(char *s) +{ +	printk(KERN_NOTICE PREFIX +	       "ACPI: Predefined validation mechanism disabled\n"); +	acpi_gbl_disable_auto_repair = TRUE; -acpi_status -acpi_os_invalidate_address( -    u8                   space_id, -    acpi_physical_address   address, -    acpi_size               length) -{ -	struct acpi_res_list res; - -	switch (space_id) { -	case ACPI_ADR_SPACE_SYSTEM_IO: -	case ACPI_ADR_SPACE_SYSTEM_MEMORY: -		/* Only interference checks against SystemIO and SystemMemory -		   are needed */ -		res.start = address; -		res.end = address + length - 1; -		res.resource_type = space_id; -		spin_lock(&acpi_res_lock); -		acpi_res_list_del(&res); -		spin_unlock(&acpi_res_lock); -		break; -	case ACPI_ADR_SPACE_PCI_CONFIG: -	case ACPI_ADR_SPACE_EC: -	case ACPI_ADR_SPACE_SMBUS: -	case ACPI_ADR_SPACE_CMOS: -	case ACPI_ADR_SPACE_PCI_BAR_TARGET: -	case ACPI_ADR_SPACE_DATA_TABLE: -	case ACPI_ADR_SPACE_FIXED_HARDWARE: -		break; -	} -	return AE_OK; +	return 1;  } -/****************************************************************************** - * - * FUNCTION:    acpi_os_validate_address - * - * PARAMETERS:  space_id             - ACPI space ID - *              address             - Physical address - *              length              - Address length - * - * RETURN:      AE_OK if address/length is valid for the space_id. Otherwise, - *              should return AE_AML_ILLEGAL_ADDRESS. - * - * DESCRIPTION: Validate a system address via the host OS. Used to validate - *              the addresses accessed by AML operation regions. - * - *****************************************************************************/ - -acpi_status -acpi_os_validate_address ( -    u8                   space_id, -    acpi_physical_address   address, -    acpi_size               length, -    char *name) -{ -	struct acpi_res_list *res; -	int added; -	if (acpi_enforce_resources == ENFORCE_RESOURCES_NO) -		return AE_OK; - -	switch (space_id) { -	case ACPI_ADR_SPACE_SYSTEM_IO: -	case ACPI_ADR_SPACE_SYSTEM_MEMORY: -		/* Only interference checks against SystemIO and SystemMemory -		   are needed */ -		res = kzalloc(sizeof(struct acpi_res_list), GFP_KERNEL); -		if (!res) -			return AE_OK; -		/* ACPI names are fixed to 4 bytes, still better use strlcpy */ -		strlcpy(res->name, name, 5); -		res->start = address; -		res->end = address + length - 1; -		res->resource_type = space_id; -		spin_lock(&acpi_res_lock); -		added = acpi_res_list_add(res); -		spin_unlock(&acpi_res_lock); -		pr_debug("%s %s resource: start: 0x%llx, end: 0x%llx, " -			 "name: %s\n", added ? "Added" : "Already exist", -			 (space_id == ACPI_ADR_SPACE_SYSTEM_IO) -			 ? "SystemIO" : "System Memory", -			 (unsigned long long)res->start, -			 (unsigned long long)res->end, -			 res->name); -		if (!added) -			kfree(res); -		break; -	case ACPI_ADR_SPACE_PCI_CONFIG: -	case ACPI_ADR_SPACE_EC: -	case ACPI_ADR_SPACE_SMBUS: -	case ACPI_ADR_SPACE_CMOS: -	case ACPI_ADR_SPACE_PCI_BAR_TARGET: -	case ACPI_ADR_SPACE_DATA_TABLE: -	case ACPI_ADR_SPACE_FIXED_HARDWARE: -		break; -	} -	return AE_OK; -} -#endif +__setup("acpica_no_return_repair", acpi_disable_return_repair);  acpi_status __init acpi_os_initialize(void)  { @@ -1526,15 +1811,25 @@ acpi_status __init acpi_os_initialize(void)  	acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1b_event_block);  	acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe0_block);  	acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe1_block); +	if (acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) { +		/* +		 * Use acpi_os_map_generic_address to pre-map the reset +		 * register if it's in system memory. +		 */ +		int rv; + +		rv = acpi_os_map_generic_address(&acpi_gbl_FADT.reset_register); +		pr_debug(PREFIX "%s: map reset_reg status %d\n", __func__, rv); +	}  	return AE_OK;  } -acpi_status acpi_os_initialize1(void) +acpi_status __init acpi_os_initialize1(void)  { -	kacpid_wq = create_workqueue("kacpid"); -	kacpi_notify_wq = create_workqueue("kacpi_notify"); -	kacpi_hotplug_wq = create_workqueue("kacpi_hotplug"); +	kacpid_wq = alloc_workqueue("kacpid", 0, 1); +	kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1); +	kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0);  	BUG_ON(!kacpid_wq);  	BUG_ON(!kacpi_notify_wq);  	BUG_ON(!kacpi_hotplug_wq); @@ -1546,7 +1841,7 @@ acpi_status acpi_os_initialize1(void)  acpi_status acpi_os_terminate(void)  {  	if (acpi_irq_handler) { -		acpi_os_remove_interrupt_handler(acpi_irq_irq, +		acpi_os_remove_interrupt_handler(acpi_gbl_FADT.sci_interrupt,  						 acpi_irq_handler);  	} @@ -1554,6 +1849,8 @@ acpi_status acpi_os_terminate(void)  	acpi_os_unmap_generic_address(&acpi_gbl_FADT.xgpe0_block);  	acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1b_event_block);  	acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1a_event_block); +	if (acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) +		acpi_os_unmap_generic_address(&acpi_gbl_FADT.reset_register);  	destroy_workqueue(kacpid_wq);  	destroy_workqueue(kacpi_notify_wq); @@ -1561,3 +1858,45 @@ acpi_status acpi_os_terminate(void)  	return AE_OK;  } + +acpi_status acpi_os_prepare_sleep(u8 sleep_state, u32 pm1a_control, +				  u32 pm1b_control) +{ +	int rc = 0; +	if (__acpi_os_prepare_sleep) +		rc = __acpi_os_prepare_sleep(sleep_state, +					     pm1a_control, pm1b_control); +	if (rc < 0) +		return AE_ERROR; +	else if (rc > 0) +		return AE_CTRL_SKIP; + +	return AE_OK; +} + +void acpi_os_set_prepare_sleep(int (*func)(u8 sleep_state, +			       u32 pm1a_ctrl, u32 pm1b_ctrl)) +{ +	__acpi_os_prepare_sleep = func; +} + +acpi_status acpi_os_prepare_extended_sleep(u8 sleep_state, u32 val_a, +				  u32 val_b) +{ +	int rc = 0; +	if (__acpi_os_prepare_extended_sleep) +		rc = __acpi_os_prepare_extended_sleep(sleep_state, +					     val_a, val_b); +	if (rc < 0) +		return AE_ERROR; +	else if (rc > 0) +		return AE_CTRL_SKIP; + +	return AE_OK; +} + +void acpi_os_set_prepare_extended_sleep(int (*func)(u8 sleep_state, +			       u32 val_a, u32 val_b)) +{ +	__acpi_os_prepare_extended_sleep = func; +}  | 
