blob: 6652c492939123b99bfb7b02f7d38354f7ab3cef [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * acpi_osl.c - OS-dependent functions ($Revision: 83 $)
3 *
4 * Copyright (C) 2000 Andrew Henroid
5 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
6 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
Matthew Wilcoxf1241c82008-03-14 13:43:13 -04007 * Copyright (c) 2008 Intel Corporation
8 * Author: Matthew Wilcox <willy@linux.intel.com>
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 *
10 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 *
26 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
27 *
28 */
29
Linus Torvalds1da177e2005-04-16 15:20:36 -070030#include <linux/module.h>
31#include <linux/kernel.h>
32#include <linux/slab.h>
33#include <linux/mm.h>
34#include <linux/pci.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include <linux/interrupt.h>
36#include <linux/kmod.h>
37#include <linux/delay.h>
38#include <linux/workqueue.h>
39#include <linux/nmi.h>
Alexey Starikovskiyad71860a2007-02-02 19:48:19 +030040#include <linux/acpi.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <linux/efi.h>
Thomas Renningerdf92e692008-02-04 23:31:22 -080042#include <linux/ioport.h>
43#include <linux/list.h>
Matthew Wilcoxf1241c82008-03-14 13:43:13 -040044#include <linux/jiffies.h>
45#include <linux/semaphore.h>
46
47#include <asm/io.h>
48#include <asm/uaccess.h>
49
50#include <acpi/acpi.h>
51#include <acpi/acpi_bus.h>
52#include <acpi/processor.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
Linus Torvalds1da177e2005-04-16 15:20:36 -070054#define _COMPONENT ACPI_OS_SERVICES
Len Brownf52fd662007-02-12 22:42:12 -050055ACPI_MODULE_NAME("osl");
Linus Torvalds1da177e2005-04-16 15:20:36 -070056#define PREFIX "ACPI: "
Len Brown4be44fc2005-08-05 00:44:28 -040057struct acpi_os_dpc {
58 acpi_osd_exec_callback function;
59 void *context;
David Howells65f27f32006-11-22 14:55:48 +000060 struct work_struct work;
Bjorn Helgaas9ac61852009-08-31 22:32:10 +000061 int wait;
Linus Torvalds1da177e2005-04-16 15:20:36 -070062};
63
64#ifdef CONFIG_ACPI_CUSTOM_DSDT
65#include CONFIG_ACPI_CUSTOM_DSDT_FILE
66#endif
67
68#ifdef ENABLE_DEBUGGER
69#include <linux/kdb.h>
70
71/* stuff for debugger support */
72int acpi_in_debugger;
73EXPORT_SYMBOL(acpi_in_debugger);
74
75extern char line_buf[80];
Len Brown4be44fc2005-08-05 00:44:28 -040076#endif /*ENABLE_DEBUGGER */
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
78static unsigned int acpi_irq_irq;
79static acpi_osd_handler acpi_irq_handler;
80static void *acpi_irq_context;
81static struct workqueue_struct *kacpid_wq;
Alexey Starikovskiy88db5e12007-05-09 23:31:03 -040082static struct workqueue_struct *kacpi_notify_wq;
Zhang Ruic02256b2009-06-23 10:20:29 +080083static struct workqueue_struct *kacpi_hotplug_wq;
Linus Torvalds1da177e2005-04-16 15:20:36 -070084
Thomas Renningerdf92e692008-02-04 23:31:22 -080085struct acpi_res_list {
86 resource_size_t start;
87 resource_size_t end;
88 acpi_adr_space_type resource_type; /* IO port, System memory, ...*/
89 char name[5]; /* only can have a length of 4 chars, make use of this
90 one instead of res->name, no need to kalloc then */
91 struct list_head resource_list;
Lin Minga5fe1a02009-08-13 10:43:27 +080092 int count;
Thomas Renningerdf92e692008-02-04 23:31:22 -080093};
94
95static LIST_HEAD(resource_list_head);
96static DEFINE_SPINLOCK(acpi_res_lock);
97
Len Brownae00d812007-05-29 18:43:33 -040098#define OSI_STRING_LENGTH_MAX 64 /* arbitrary */
Lin Mingb0ed7a92010-08-06 09:35:51 +080099static char osi_setup_string[OSI_STRING_LENGTH_MAX];
100
101static void __init acpi_osi_setup_late(void);
Len Brownae00d812007-05-29 18:43:33 -0400102
Len Brownd4b7dc42008-01-23 20:50:56 -0500103/*
Len Browna6e08872008-11-08 01:21:10 -0500104 * The story of _OSI(Linux)
Len Brownd4b7dc42008-01-23 20:50:56 -0500105 *
Len Browna6e08872008-11-08 01:21:10 -0500106 * From pre-history through Linux-2.6.22,
107 * Linux responded TRUE upon a BIOS OSI(Linux) query.
Len Brownd4b7dc42008-01-23 20:50:56 -0500108 *
Len Browna6e08872008-11-08 01:21:10 -0500109 * Unfortunately, reference BIOS writers got wind of this
110 * and put OSI(Linux) in their example code, quickly exposing
111 * this string as ill-conceived and opening the door to
112 * an un-bounded number of BIOS incompatibilities.
Len Brownd4b7dc42008-01-23 20:50:56 -0500113 *
Len Browna6e08872008-11-08 01:21:10 -0500114 * For example, OSI(Linux) was used on resume to re-POST a
115 * video card on one system, because Linux at that time
116 * could not do a speedy restore in its native driver.
117 * But then upon gaining quick native restore capability,
118 * Linux has no way to tell the BIOS to skip the time-consuming
119 * POST -- putting Linux at a permanent performance disadvantage.
120 * On another system, the BIOS writer used OSI(Linux)
121 * to infer native OS support for IPMI! On other systems,
122 * OSI(Linux) simply got in the way of Linux claiming to
123 * be compatible with other operating systems, exposing
124 * BIOS issues such as skipped device initialization.
Len Brownd4b7dc42008-01-23 20:50:56 -0500125 *
Len Browna6e08872008-11-08 01:21:10 -0500126 * So "Linux" turned out to be a really poor chose of
127 * OSI string, and from Linux-2.6.23 onward we respond FALSE.
Len Brownd4b7dc42008-01-23 20:50:56 -0500128 *
129 * BIOS writers should NOT query _OSI(Linux) on future systems.
Len Browna6e08872008-11-08 01:21:10 -0500130 * Linux will complain on the console when it sees it, and return FALSE.
131 * To get Linux to return TRUE for your system will require
132 * a kernel source update to add a DMI entry,
133 * or boot with "acpi_osi=Linux"
Len Brownd4b7dc42008-01-23 20:50:56 -0500134 */
Len Brownd4b7dc42008-01-23 20:50:56 -0500135
Adrian Bunk1d15d842008-01-29 00:10:15 +0200136static struct osi_linux {
Len Brownd4b7dc42008-01-23 20:50:56 -0500137 unsigned int enable:1;
138 unsigned int dmi:1;
139 unsigned int cmdline:1;
140 unsigned int known:1;
Len Browna6e08872008-11-08 01:21:10 -0500141} osi_linux = { 0, 0, 0, 0};
Len Brownf5076542007-05-30 00:10:38 -0400142
Lin Mingb0ed7a92010-08-06 09:35:51 +0800143static u32 acpi_osi_handler(acpi_string interface, u32 supported)
144{
145 if (!strcmp("Linux", interface)) {
146
147 printk(KERN_NOTICE PREFIX
148 "BIOS _OSI(Linux) query %s%s\n",
149 osi_linux.enable ? "honored" : "ignored",
150 osi_linux.cmdline ? " via cmdline" :
151 osi_linux.dmi ? " via DMI" : "");
152 }
153
154 return supported;
155}
156
Bjorn Helgaas9a47cdb2007-01-18 16:42:55 -0700157static void __init acpi_request_region (struct acpi_generic_address *addr,
158 unsigned int length, char *desc)
159{
Bjorn Helgaas9a47cdb2007-01-18 16:42:55 -0700160 if (!addr->address || !length)
161 return;
162
Andi Kleencfa806f2010-07-20 15:18:36 -0700163 /* Resources are never freed */
Len Browneee3c852007-02-03 01:38:16 -0500164 if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_IO)
Andi Kleencfa806f2010-07-20 15:18:36 -0700165 request_region(addr->address, length, desc);
Len Browneee3c852007-02-03 01:38:16 -0500166 else if (addr->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
Andi Kleencfa806f2010-07-20 15:18:36 -0700167 request_mem_region(addr->address, length, desc);
Bjorn Helgaas9a47cdb2007-01-18 16:42:55 -0700168}
169
170static int __init acpi_reserve_resources(void)
171{
Len Browneee3c852007-02-03 01:38:16 -0500172 acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length,
Bjorn Helgaas9a47cdb2007-01-18 16:42:55 -0700173 "ACPI PM1a_EVT_BLK");
174
Len Browneee3c852007-02-03 01:38:16 -0500175 acpi_request_region(&acpi_gbl_FADT.xpm1b_event_block, acpi_gbl_FADT.pm1_event_length,
Bjorn Helgaas9a47cdb2007-01-18 16:42:55 -0700176 "ACPI PM1b_EVT_BLK");
177
Len Browneee3c852007-02-03 01:38:16 -0500178 acpi_request_region(&acpi_gbl_FADT.xpm1a_control_block, acpi_gbl_FADT.pm1_control_length,
Bjorn Helgaas9a47cdb2007-01-18 16:42:55 -0700179 "ACPI PM1a_CNT_BLK");
180
Len Browneee3c852007-02-03 01:38:16 -0500181 acpi_request_region(&acpi_gbl_FADT.xpm1b_control_block, acpi_gbl_FADT.pm1_control_length,
Bjorn Helgaas9a47cdb2007-01-18 16:42:55 -0700182 "ACPI PM1b_CNT_BLK");
183
Len Browneee3c852007-02-03 01:38:16 -0500184 if (acpi_gbl_FADT.pm_timer_length == 4)
185 acpi_request_region(&acpi_gbl_FADT.xpm_timer_block, 4, "ACPI PM_TMR");
Bjorn Helgaas9a47cdb2007-01-18 16:42:55 -0700186
Len Browneee3c852007-02-03 01:38:16 -0500187 acpi_request_region(&acpi_gbl_FADT.xpm2_control_block, acpi_gbl_FADT.pm2_control_length,
Bjorn Helgaas9a47cdb2007-01-18 16:42:55 -0700188 "ACPI PM2_CNT_BLK");
189
190 /* Length of GPE blocks must be a non-negative multiple of 2 */
191
Len Browneee3c852007-02-03 01:38:16 -0500192 if (!(acpi_gbl_FADT.gpe0_block_length & 0x1))
193 acpi_request_region(&acpi_gbl_FADT.xgpe0_block,
194 acpi_gbl_FADT.gpe0_block_length, "ACPI GPE0_BLK");
Bjorn Helgaas9a47cdb2007-01-18 16:42:55 -0700195
Len Browneee3c852007-02-03 01:38:16 -0500196 if (!(acpi_gbl_FADT.gpe1_block_length & 0x1))
197 acpi_request_region(&acpi_gbl_FADT.xgpe1_block,
198 acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK");
Bjorn Helgaas9a47cdb2007-01-18 16:42:55 -0700199
200 return 0;
201}
202device_initcall(acpi_reserve_resources);
203
Len Browndd272b52007-05-30 00:26:11 -0400204acpi_status __init acpi_os_initialize(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205{
206 return AE_OK;
207}
208
Len Brown4be44fc2005-08-05 00:44:28 -0400209acpi_status acpi_os_initialize1(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210{
Tejun Heo8fec62b2010-06-29 10:07:09 +0200211 kacpid_wq = create_workqueue("kacpid");
212 kacpi_notify_wq = create_workqueue("kacpi_notify");
213 kacpi_hotplug_wq = create_workqueue("kacpi_hotplug");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 BUG_ON(!kacpid_wq);
Alexey Starikovskiy88db5e12007-05-09 23:31:03 -0400215 BUG_ON(!kacpi_notify_wq);
Zhang Ruic02256b2009-06-23 10:20:29 +0800216 BUG_ON(!kacpi_hotplug_wq);
Lin Mingb0ed7a92010-08-06 09:35:51 +0800217 acpi_install_interface_handler(acpi_osi_handler);
218 acpi_osi_setup_late();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 return AE_OK;
220}
221
Len Brown4be44fc2005-08-05 00:44:28 -0400222acpi_status acpi_os_terminate(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223{
224 if (acpi_irq_handler) {
225 acpi_os_remove_interrupt_handler(acpi_irq_irq,
226 acpi_irq_handler);
227 }
228
229 destroy_workqueue(kacpid_wq);
Alexey Starikovskiy88db5e12007-05-09 23:31:03 -0400230 destroy_workqueue(kacpi_notify_wq);
Zhang Ruic02256b2009-06-23 10:20:29 +0800231 destroy_workqueue(kacpi_hotplug_wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700232
233 return AE_OK;
234}
235
Len Brown4be44fc2005-08-05 00:44:28 -0400236void acpi_os_printf(const char *fmt, ...)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700237{
238 va_list args;
239 va_start(args, fmt);
240 acpi_os_vprintf(fmt, args);
241 va_end(args);
242}
Len Brown4be44fc2005-08-05 00:44:28 -0400243
Len Brown4be44fc2005-08-05 00:44:28 -0400244void acpi_os_vprintf(const char *fmt, va_list args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700245{
246 static char buffer[512];
Len Brown4be44fc2005-08-05 00:44:28 -0400247
Linus Torvalds1da177e2005-04-16 15:20:36 -0700248 vsprintf(buffer, fmt, args);
249
250#ifdef ENABLE_DEBUGGER
251 if (acpi_in_debugger) {
252 kdb_printf("%s", buffer);
253 } else {
Frank Seidel4d939152009-02-04 17:03:07 +0100254 printk(KERN_CONT "%s", buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 }
256#else
Frank Seidel4d939152009-02-04 17:03:07 +0100257 printk(KERN_CONT "%s", buffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700258#endif
259}
260
Alexey Starikovskiyad71860a2007-02-02 19:48:19 +0300261acpi_physical_address __init acpi_os_get_root_pointer(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262{
263 if (efi_enabled) {
Bjorn Helgaasb2c99e32006-03-26 01:37:08 -0800264 if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
Alexey Starikovskiyad71860a2007-02-02 19:48:19 +0300265 return efi.acpi20;
Bjorn Helgaasb2c99e32006-03-26 01:37:08 -0800266 else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
Alexey Starikovskiyad71860a2007-02-02 19:48:19 +0300267 return efi.acpi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700268 else {
Len Brown4be44fc2005-08-05 00:44:28 -0400269 printk(KERN_ERR PREFIX
270 "System description tables not found\n");
Alexey Starikovskiyad71860a2007-02-02 19:48:19 +0300271 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 }
Len Brown239665a2007-11-23 20:08:02 -0500273 } else {
274 acpi_physical_address pa = 0;
275
276 acpi_find_root_pointer(&pa);
277 return pa;
278 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279}
280
Jan Beulich2fdf0742007-12-13 08:33:59 +0000281void __iomem *__init_refok
282acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700283{
Bjorn Helgaas9f4fd612006-03-26 01:37:10 -0800284 if (phys > ULONG_MAX) {
285 printk(KERN_ERR PREFIX "Cannot map memory that high\n");
Randy Dunlap70c08462007-02-13 16:11:36 -0800286 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 }
Alexey Starikovskiyad71860a2007-02-02 19:48:19 +0300288 if (acpi_gbl_permanent_mmap)
289 /*
290 * ioremap checks to ensure this is in reserved space
291 */
292 return ioremap((unsigned long)phys, size);
293 else
294 return __acpi_map_table((unsigned long)phys, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700295}
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800296EXPORT_SYMBOL_GPL(acpi_os_map_memory);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297
Jeremy Fitzhardinge0d3a9cf2009-02-22 14:58:56 -0800298void __ref acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299{
Yinghai Lu7d972772009-02-07 15:39:41 -0800300 if (acpi_gbl_permanent_mmap)
Alexey Starikovskiyad71860a2007-02-02 19:48:19 +0300301 iounmap(virt);
Yinghai Lu7d972772009-02-07 15:39:41 -0800302 else
303 __acpi_unmap_table(virt, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700304}
Kylene Jo Hall55a82ab2006-01-08 01:03:15 -0800305EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306
Jeremy Fitzhardinge0d3a9cf2009-02-22 14:58:56 -0800307void __init early_acpi_os_unmap_memory(void __iomem *virt, acpi_size size)
Yinghai Lu7d972772009-02-07 15:39:41 -0800308{
309 if (!acpi_gbl_permanent_mmap)
310 __acpi_unmap_table(virt, size);
311}
312
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313#ifdef ACPI_FUTURE_USAGE
314acpi_status
Len Brown4be44fc2005-08-05 00:44:28 -0400315acpi_os_get_physical_address(void *virt, acpi_physical_address * phys)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316{
Len Brown4be44fc2005-08-05 00:44:28 -0400317 if (!phys || !virt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318 return AE_BAD_PARAMETER;
319
320 *phys = virt_to_phys(virt);
321
322 return AE_OK;
323}
324#endif
325
326#define ACPI_MAX_OVERRIDE_LEN 100
327
328static char acpi_os_name[ACPI_MAX_OVERRIDE_LEN];
329
330acpi_status
Len Brown4be44fc2005-08-05 00:44:28 -0400331acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
332 acpi_string * new_val)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700333{
334 if (!init_val || !new_val)
335 return AE_BAD_PARAMETER;
336
337 *new_val = NULL;
Len Brown4be44fc2005-08-05 00:44:28 -0400338 if (!memcmp(init_val->name, "_OS_", 4) && strlen(acpi_os_name)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700339 printk(KERN_INFO PREFIX "Overriding _OS definition to '%s'\n",
Len Brown4be44fc2005-08-05 00:44:28 -0400340 acpi_os_name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700341 *new_val = acpi_os_name;
342 }
343
344 return AE_OK;
345}
346
347acpi_status
Len Brown4be44fc2005-08-05 00:44:28 -0400348acpi_os_table_override(struct acpi_table_header * existing_table,
349 struct acpi_table_header ** new_table)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700350{
351 if (!existing_table || !new_table)
352 return AE_BAD_PARAMETER;
353
Markus Gaugusch71fc47a2008-02-05 00:04:06 +0100354 *new_table = NULL;
355
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356#ifdef CONFIG_ACPI_CUSTOM_DSDT
357 if (strncmp(existing_table->signature, "DSDT", 4) == 0)
Len Brown4be44fc2005-08-05 00:44:28 -0400358 *new_table = (struct acpi_table_header *)AmlCode;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359#endif
Éric Piel6ed31e92008-02-05 00:04:50 +0100360 if (*new_table != NULL) {
361 printk(KERN_WARNING PREFIX "Override [%4.4s-%8.8s], "
362 "this is unsafe: tainting kernel\n",
363 existing_table->signature,
364 existing_table->oem_table_id);
365 add_taint(TAINT_OVERRIDDEN_ACPI_TABLE);
366 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 return AE_OK;
368}
369
David Howells7d12e782006-10-05 14:55:46 +0100370static irqreturn_t acpi_irq(int irq, void *dev_id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700371{
Len Brown5229e872008-02-06 01:26:55 -0500372 u32 handled;
373
374 handled = (*acpi_irq_handler) (acpi_irq_context);
375
376 if (handled) {
377 acpi_irq_handled++;
378 return IRQ_HANDLED;
Len Brown88bea182009-04-21 00:35:47 -0400379 } else {
380 acpi_irq_not_handled++;
Len Brown5229e872008-02-06 01:26:55 -0500381 return IRQ_NONE;
Len Brown88bea182009-04-21 00:35:47 -0400382 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383}
384
385acpi_status
Len Brown4be44fc2005-08-05 00:44:28 -0400386acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
387 void *context)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388{
389 unsigned int irq;
390
Len Brown5229e872008-02-06 01:26:55 -0500391 acpi_irq_stats_init();
392
Linus Torvalds1da177e2005-04-16 15:20:36 -0700393 /*
394 * Ignore the GSI from the core, and use the value in our copy of the
395 * FADT. It may not be the same if an interrupt source override exists
396 * for the SCI.
397 */
Alexey Starikovskiycee324b2007-02-02 19:48:22 +0300398 gsi = acpi_gbl_FADT.sci_interrupt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700399 if (acpi_gsi_to_irq(gsi, &irq) < 0) {
400 printk(KERN_ERR PREFIX "SCI (ACPI GSI %d) not registered\n",
401 gsi);
402 return AE_OK;
403 }
404
405 acpi_irq_handler = handler;
406 acpi_irq_context = context;
Thomas Gleixnerdace1452006-07-01 19:29:38 -0700407 if (request_irq(irq, acpi_irq, IRQF_SHARED, "acpi", acpi_irq)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700408 printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq);
409 return AE_NOT_ACQUIRED;
410 }
411 acpi_irq_irq = irq;
412
413 return AE_OK;
414}
415
Len Brown4be44fc2005-08-05 00:44:28 -0400416acpi_status acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417{
418 if (irq) {
419 free_irq(irq, acpi_irq);
420 acpi_irq_handler = NULL;
421 acpi_irq_irq = 0;
422 }
423
424 return AE_OK;
425}
426
427/*
428 * Running in interpreter thread context, safe to sleep
429 */
430
Lin Ming439913f2010-01-28 10:53:19 +0800431void acpi_os_sleep(u64 ms)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432{
Nishanth Aravamudan01a527e2005-11-07 01:01:14 -0800433 schedule_timeout_interruptible(msecs_to_jiffies(ms));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700434}
Len Brown4be44fc2005-08-05 00:44:28 -0400435
Len Brown4be44fc2005-08-05 00:44:28 -0400436void acpi_os_stall(u32 us)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437{
438 while (us) {
439 u32 delay = 1000;
440
441 if (delay > us)
442 delay = us;
443 udelay(delay);
444 touch_nmi_watchdog();
445 us -= delay;
446 }
447}
Len Brown4be44fc2005-08-05 00:44:28 -0400448
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449/*
450 * Support ACPI 3.0 AML Timer operand
451 * Returns 64-bit free-running, monotonically increasing timer
452 * with 100ns granularity
453 */
Len Brown4be44fc2005-08-05 00:44:28 -0400454u64 acpi_os_get_timer(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700455{
456 static u64 t;
457
458#ifdef CONFIG_HPET
459 /* TBD: use HPET if available */
460#endif
461
462#ifdef CONFIG_X86_PM_TIMER
463 /* TBD: default to PM timer if HPET was not available */
464#endif
465 if (!t)
466 printk(KERN_ERR PREFIX "acpi_os_get_timer() TBD\n");
467
468 return ++t;
469}
470
Len Brown4be44fc2005-08-05 00:44:28 -0400471acpi_status acpi_os_read_port(acpi_io_address port, u32 * value, u32 width)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472{
473 u32 dummy;
474
475 if (!value)
476 value = &dummy;
477
Zhao Yakui49fbabf2007-11-15 17:01:06 +0800478 *value = 0;
479 if (width <= 8) {
Len Brown4be44fc2005-08-05 00:44:28 -0400480 *(u8 *) value = inb(port);
Zhao Yakui49fbabf2007-11-15 17:01:06 +0800481 } else if (width <= 16) {
Len Brown4be44fc2005-08-05 00:44:28 -0400482 *(u16 *) value = inw(port);
Zhao Yakui49fbabf2007-11-15 17:01:06 +0800483 } else if (width <= 32) {
Len Brown4be44fc2005-08-05 00:44:28 -0400484 *(u32 *) value = inl(port);
Zhao Yakui49fbabf2007-11-15 17:01:06 +0800485 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 BUG();
487 }
488
489 return AE_OK;
490}
Len Brown4be44fc2005-08-05 00:44:28 -0400491
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492EXPORT_SYMBOL(acpi_os_read_port);
493
Len Brown4be44fc2005-08-05 00:44:28 -0400494acpi_status acpi_os_write_port(acpi_io_address port, u32 value, u32 width)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495{
Zhao Yakui49fbabf2007-11-15 17:01:06 +0800496 if (width <= 8) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 outb(value, port);
Zhao Yakui49fbabf2007-11-15 17:01:06 +0800498 } else if (width <= 16) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700499 outw(value, port);
Zhao Yakui49fbabf2007-11-15 17:01:06 +0800500 } else if (width <= 32) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700501 outl(value, port);
Zhao Yakui49fbabf2007-11-15 17:01:06 +0800502 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 BUG();
504 }
505
506 return AE_OK;
507}
Len Brown4be44fc2005-08-05 00:44:28 -0400508
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509EXPORT_SYMBOL(acpi_os_write_port);
510
511acpi_status
Len Brown4be44fc2005-08-05 00:44:28 -0400512acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513{
Len Brown4be44fc2005-08-05 00:44:28 -0400514 u32 dummy;
515 void __iomem *virt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516
Bjorn Helgaas9f4fd612006-03-26 01:37:10 -0800517 virt_addr = ioremap(phys_addr, width);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 if (!value)
519 value = &dummy;
520
521 switch (width) {
522 case 8:
Len Brown4be44fc2005-08-05 00:44:28 -0400523 *(u8 *) value = readb(virt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524 break;
525 case 16:
Len Brown4be44fc2005-08-05 00:44:28 -0400526 *(u16 *) value = readw(virt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 break;
528 case 32:
Len Brown4be44fc2005-08-05 00:44:28 -0400529 *(u32 *) value = readl(virt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 break;
531 default:
532 BUG();
533 }
534
Bjorn Helgaas9f4fd612006-03-26 01:37:10 -0800535 iounmap(virt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536
537 return AE_OK;
538}
539
540acpi_status
Len Brown4be44fc2005-08-05 00:44:28 -0400541acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700542{
Len Brown4be44fc2005-08-05 00:44:28 -0400543 void __iomem *virt_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544
Bjorn Helgaas9f4fd612006-03-26 01:37:10 -0800545 virt_addr = ioremap(phys_addr, width);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546
547 switch (width) {
548 case 8:
549 writeb(value, virt_addr);
550 break;
551 case 16:
552 writew(value, virt_addr);
553 break;
554 case 32:
555 writel(value, virt_addr);
556 break;
557 default:
558 BUG();
559 }
560
Bjorn Helgaas9f4fd612006-03-26 01:37:10 -0800561 iounmap(virt_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
563 return AE_OK;
564}
565
Linus Torvalds1da177e2005-04-16 15:20:36 -0700566acpi_status
Len Brown4be44fc2005-08-05 00:44:28 -0400567acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
Bob Moorec5f02312010-08-06 08:57:53 +0800568 u64 *value, u32 width)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700569{
570 int result, size;
Bob Moorec5f02312010-08-06 08:57:53 +0800571 u32 value32;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572
573 if (!value)
574 return AE_BAD_PARAMETER;
575
576 switch (width) {
577 case 8:
578 size = 1;
579 break;
580 case 16:
581 size = 2;
582 break;
583 case 32:
584 size = 4;
585 break;
586 default:
587 return AE_ERROR;
588 }
589
Matthew Wilcoxb6ce0682008-02-10 09:45:28 -0500590 result = raw_pci_read(pci_id->segment, pci_id->bus,
591 PCI_DEVFN(pci_id->device, pci_id->function),
Bob Moorec5f02312010-08-06 08:57:53 +0800592 reg, size, &value32);
593 *value = value32;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594
595 return (result ? AE_ERROR : AE_OK);
596}
Len Brown4be44fc2005-08-05 00:44:28 -0400597
Linus Torvalds1da177e2005-04-16 15:20:36 -0700598acpi_status
Len Brown4be44fc2005-08-05 00:44:28 -0400599acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
Lin Ming439913f2010-01-28 10:53:19 +0800600 u64 value, u32 width)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601{
602 int result, size;
603
604 switch (width) {
605 case 8:
606 size = 1;
607 break;
608 case 16:
609 size = 2;
610 break;
611 case 32:
612 size = 4;
613 break;
614 default:
615 return AE_ERROR;
616 }
617
Matthew Wilcoxb6ce0682008-02-10 09:45:28 -0500618 result = raw_pci_write(pci_id->segment, pci_id->bus,
619 PCI_DEVFN(pci_id->device, pci_id->function),
620 reg, size, value);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621
622 return (result ? AE_ERROR : AE_OK);
623}
624
625/* TODO: Change code to take advantage of driver model more */
Len Brown4be44fc2005-08-05 00:44:28 -0400626static void acpi_os_derive_pci_id_2(acpi_handle rhandle, /* upper bound */
627 acpi_handle chandle, /* current node */
628 struct acpi_pci_id **id,
629 int *is_bridge, u8 * bus_number)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700630{
Len Brown4be44fc2005-08-05 00:44:28 -0400631 acpi_handle handle;
632 struct acpi_pci_id *pci_id = *id;
633 acpi_status status;
Matthew Wilcox27663c52008-10-10 02:22:59 -0400634 unsigned long long temp;
Len Brown4be44fc2005-08-05 00:44:28 -0400635 acpi_object_type type;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700636
637 acpi_get_parent(chandle, &handle);
638 if (handle != rhandle) {
Len Brown4be44fc2005-08-05 00:44:28 -0400639 acpi_os_derive_pci_id_2(rhandle, handle, &pci_id, is_bridge,
640 bus_number);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700641
642 status = acpi_get_type(handle, &type);
Len Brown4be44fc2005-08-05 00:44:28 -0400643 if ((ACPI_FAILURE(status)) || (type != ACPI_TYPE_DEVICE))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 return;
645
Matthew Wilcox27663c52008-10-10 02:22:59 -0400646 status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL,
Len Brown4be44fc2005-08-05 00:44:28 -0400647 &temp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 if (ACPI_SUCCESS(status)) {
Bob Moorec5f02312010-08-06 08:57:53 +0800649 u64 val;
Len Brown4be44fc2005-08-05 00:44:28 -0400650 pci_id->device = ACPI_HIWORD(ACPI_LODWORD(temp));
651 pci_id->function = ACPI_LOWORD(ACPI_LODWORD(temp));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652
653 if (*is_bridge)
654 pci_id->bus = *bus_number;
655
656 /* any nicer way to get bus number of bridge ? */
Len Brown4be44fc2005-08-05 00:44:28 -0400657 status =
Linus Torvalds10270d42008-02-13 09:56:14 -0800658 acpi_os_read_pci_configuration(pci_id, 0x0e, &val,
Len Brown4be44fc2005-08-05 00:44:28 -0400659 8);
660 if (ACPI_SUCCESS(status)
Linus Torvalds10270d42008-02-13 09:56:14 -0800661 && ((val & 0x7f) == 1 || (val & 0x7f) == 2)) {
Len Brown4be44fc2005-08-05 00:44:28 -0400662 status =
663 acpi_os_read_pci_configuration(pci_id, 0x18,
Linus Torvalds10270d42008-02-13 09:56:14 -0800664 &val, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 if (!ACPI_SUCCESS(status)) {
666 /* Certainly broken... FIX ME */
667 return;
668 }
669 *is_bridge = 1;
Linus Torvalds10270d42008-02-13 09:56:14 -0800670 pci_id->bus = val;
Len Brown4be44fc2005-08-05 00:44:28 -0400671 status =
672 acpi_os_read_pci_configuration(pci_id, 0x19,
Linus Torvalds10270d42008-02-13 09:56:14 -0800673 &val, 8);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 if (ACPI_SUCCESS(status)) {
Linus Torvalds10270d42008-02-13 09:56:14 -0800675 *bus_number = val;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700676 }
677 } else
678 *is_bridge = 0;
679 }
680 }
681}
682
Len Brown4be44fc2005-08-05 00:44:28 -0400683void acpi_os_derive_pci_id(acpi_handle rhandle, /* upper bound */
684 acpi_handle chandle, /* current node */
685 struct acpi_pci_id **id)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686{
687 int is_bridge = 1;
688 u8 bus_number = (*id)->bus;
689
690 acpi_os_derive_pci_id_2(rhandle, chandle, id, &is_bridge, &bus_number);
691}
692
David Howells65f27f32006-11-22 14:55:48 +0000693static void acpi_os_execute_deferred(struct work_struct *work)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694{
David Howells65f27f32006-11-22 14:55:48 +0000695 struct acpi_os_dpc *dpc = container_of(work, struct acpi_os_dpc, work);
Alexey Starikovskiy88db5e12007-05-09 23:31:03 -0400696
Bjorn Helgaas9ac61852009-08-31 22:32:10 +0000697 if (dpc->wait)
698 acpi_os_wait_events_complete(NULL);
Zhang Rui19cd8472008-08-28 10:05:06 +0800699
700 dpc->function(dpc->context);
701 kfree(dpc);
Zhang Rui19cd8472008-08-28 10:05:06 +0800702}
703
Alexey Starikovskiyb8d35192006-05-05 03:23:00 -0400704/*******************************************************************************
705 *
706 * FUNCTION: acpi_os_execute
707 *
708 * PARAMETERS: Type - Type of the callback
709 * Function - Function to be executed
710 * Context - Function parameters
711 *
712 * RETURN: Status
713 *
714 * DESCRIPTION: Depending on type, either queues function for deferred execution or
715 * immediately executes function on a separate thread.
716 *
717 ******************************************************************************/
718
Zhang Rui19cd8472008-08-28 10:05:06 +0800719static acpi_status __acpi_os_execute(acpi_execute_type type,
720 acpi_osd_exec_callback function, void *context, int hp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721{
Len Brown4be44fc2005-08-05 00:44:28 -0400722 acpi_status status = AE_OK;
723 struct acpi_os_dpc *dpc;
Alexey Starikovskiy17bc54e2007-11-13 13:05:45 +0300724 struct workqueue_struct *queue;
Zhang Rui19cd8472008-08-28 10:05:06 +0800725 int ret;
Len Brown72945b22006-07-12 22:46:42 -0400726 ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
727 "Scheduling function [%p(%p)] for deferred execution.\n",
728 function, context));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700729
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 /*
731 * Allocate/initialize DPC structure. Note that this memory will be
David Howells65f27f32006-11-22 14:55:48 +0000732 * freed by the callee. The kernel handles the work_struct list in a
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 * way that allows us to also free its memory inside the callee.
734 * Because we may want to schedule several tasks with different
735 * parameters we can't use the approach some kernel code uses of
David Howells65f27f32006-11-22 14:55:48 +0000736 * having a static work_struct.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 */
Len Brown72945b22006-07-12 22:46:42 -0400738
David Howells65f27f32006-11-22 14:55:48 +0000739 dpc = kmalloc(sizeof(struct acpi_os_dpc), GFP_ATOMIC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 if (!dpc)
Lin Ming889c78b2008-12-31 09:23:57 +0800741 return AE_NO_MEMORY;
Linus Torvaldsb976fe12006-11-17 19:31:09 -0800742
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 dpc->function = function;
744 dpc->context = context;
Linus Torvaldsb976fe12006-11-17 19:31:09 -0800745
Zhang Ruic02256b2009-06-23 10:20:29 +0800746 /*
747 * We can't run hotplug code in keventd_wq/kacpid_wq/kacpid_notify_wq
748 * because the hotplug code may call driver .remove() functions,
749 * which invoke flush_scheduled_work/acpi_os_wait_events_complete
750 * to flush these workqueues.
751 */
752 queue = hp ? kacpi_hotplug_wq :
753 (type == OSL_NOTIFY_HANDLER ? kacpi_notify_wq : kacpid_wq);
Bjorn Helgaas9ac61852009-08-31 22:32:10 +0000754 dpc->wait = hp ? 1 : 0;
Zhang Ruibc736752010-03-22 15:48:54 +0800755
756 if (queue == kacpi_hotplug_wq)
757 INIT_WORK(&dpc->work, acpi_os_execute_deferred);
758 else if (queue == kacpi_notify_wq)
759 INIT_WORK(&dpc->work, acpi_os_execute_deferred);
760 else
761 INIT_WORK(&dpc->work, acpi_os_execute_deferred);
762
Tejun Heo8fec62b2010-06-29 10:07:09 +0200763 /*
764 * On some machines, a software-initiated SMI causes corruption unless
765 * the SMI runs on CPU 0. An SMI can be initiated by any AML, but
766 * typically it's done in GPE-related methods that are run via
767 * workqueues, so we can avoid the known corruption cases by always
768 * queueing on CPU 0.
769 */
770 ret = queue_work_on(0, queue, &dpc->work);
Zhang Rui19cd8472008-08-28 10:05:06 +0800771
772 if (!ret) {
Lin Ming55ac9a02008-09-28 14:51:56 +0800773 printk(KERN_ERR PREFIX
774 "Call to queue_work() failed.\n");
Alexey Starikovskiy17bc54e2007-11-13 13:05:45 +0300775 status = AE_ERROR;
776 kfree(dpc);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700777 }
Lin Ming889c78b2008-12-31 09:23:57 +0800778 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779}
Len Brown4be44fc2005-08-05 00:44:28 -0400780
Zhang Rui19cd8472008-08-28 10:05:06 +0800781acpi_status acpi_os_execute(acpi_execute_type type,
782 acpi_osd_exec_callback function, void *context)
783{
784 return __acpi_os_execute(type, function, context, 0);
785}
Alexey Starikovskiyb8d35192006-05-05 03:23:00 -0400786EXPORT_SYMBOL(acpi_os_execute);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
Zhang Rui19cd8472008-08-28 10:05:06 +0800788acpi_status acpi_os_hotplug_execute(acpi_osd_exec_callback function,
789 void *context)
790{
791 return __acpi_os_execute(0, function, context, 1);
792}
793
Len Brown4be44fc2005-08-05 00:44:28 -0400794void acpi_os_wait_events_complete(void *context)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795{
796 flush_workqueue(kacpid_wq);
Zhang Rui2f67a062008-04-29 02:34:42 -0400797 flush_workqueue(kacpi_notify_wq);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798}
Len Brown4be44fc2005-08-05 00:44:28 -0400799
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800EXPORT_SYMBOL(acpi_os_wait_events_complete);
801
802/*
803 * Allocate the memory for a spinlock and initialize it.
804 */
Bob Moore967440e32006-06-23 17:04:00 -0400805acpi_status acpi_os_create_lock(acpi_spinlock * handle)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806{
Bob Moore967440e32006-06-23 17:04:00 -0400807 spin_lock_init(*handle);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700808
Patrick Mocheld550d982006-06-27 00:41:40 -0400809 return AE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810}
811
Linus Torvalds1da177e2005-04-16 15:20:36 -0700812/*
813 * Deallocate the memory for a spinlock.
814 */
Bob Moore967440e32006-06-23 17:04:00 -0400815void acpi_os_delete_lock(acpi_spinlock handle)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700816{
Patrick Mocheld550d982006-06-27 00:41:40 -0400817 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818}
819
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820acpi_status
Len Brown4be44fc2005-08-05 00:44:28 -0400821acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822{
Len Brown4be44fc2005-08-05 00:44:28 -0400823 struct semaphore *sem = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 sem = acpi_os_allocate(sizeof(struct semaphore));
826 if (!sem)
Patrick Mocheld550d982006-06-27 00:41:40 -0400827 return AE_NO_MEMORY;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 memset(sem, 0, sizeof(struct semaphore));
829
830 sema_init(sem, initial_units);
831
Len Brown4be44fc2005-08-05 00:44:28 -0400832 *handle = (acpi_handle *) sem;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833
Len Brown4be44fc2005-08-05 00:44:28 -0400834 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Creating semaphore[%p|%d].\n",
835 *handle, initial_units));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836
Patrick Mocheld550d982006-06-27 00:41:40 -0400837 return AE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840/*
841 * TODO: A better way to delete semaphores? Linux doesn't have a
842 * 'delete_semaphore()' function -- may result in an invalid
843 * pointer dereference for non-synchronized consumers. Should
844 * we at least check for blocked threads and signal/cancel them?
845 */
846
Len Brown4be44fc2005-08-05 00:44:28 -0400847acpi_status acpi_os_delete_semaphore(acpi_handle handle)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848{
Len Brown4be44fc2005-08-05 00:44:28 -0400849 struct semaphore *sem = (struct semaphore *)handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 if (!sem)
Patrick Mocheld550d982006-06-27 00:41:40 -0400852 return AE_BAD_PARAMETER;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700853
Len Brown4be44fc2005-08-05 00:44:28 -0400854 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Deleting semaphore[%p].\n", handle));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855
Matthew Wilcoxf1241c82008-03-14 13:43:13 -0400856 BUG_ON(!list_empty(&sem->wait_list));
Len Brown02438d82006-06-30 03:19:10 -0400857 kfree(sem);
Len Brown4be44fc2005-08-05 00:44:28 -0400858 sem = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859
Patrick Mocheld550d982006-06-27 00:41:40 -0400860 return AE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862
Linus Torvalds1da177e2005-04-16 15:20:36 -0700863/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700864 * TODO: Support for units > 1?
865 */
Len Brown4be44fc2005-08-05 00:44:28 -0400866acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867{
Len Brown4be44fc2005-08-05 00:44:28 -0400868 acpi_status status = AE_OK;
869 struct semaphore *sem = (struct semaphore *)handle;
Matthew Wilcoxf1241c82008-03-14 13:43:13 -0400870 long jiffies;
Len Brown4be44fc2005-08-05 00:44:28 -0400871 int ret = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873 if (!sem || (units < 1))
Patrick Mocheld550d982006-06-27 00:41:40 -0400874 return AE_BAD_PARAMETER;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875
876 if (units > 1)
Patrick Mocheld550d982006-06-27 00:41:40 -0400877 return AE_SUPPORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878
Len Brown4be44fc2005-08-05 00:44:28 -0400879 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Waiting for semaphore[%p|%d|%d]\n",
880 handle, units, timeout));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881
Matthew Wilcoxf1241c82008-03-14 13:43:13 -0400882 if (timeout == ACPI_WAIT_FOREVER)
883 jiffies = MAX_SCHEDULE_TIMEOUT;
884 else
885 jiffies = msecs_to_jiffies(timeout);
886
887 ret = down_timeout(sem, jiffies);
888 if (ret)
889 status = AE_TIME;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
891 if (ACPI_FAILURE(status)) {
Bjorn Helgaas9e7e2c02006-04-27 05:25:00 -0400892 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
Thomas Renningera6fc6722006-06-26 23:58:43 -0400893 "Failed to acquire semaphore[%p|%d|%d], %s",
Len Brown4be44fc2005-08-05 00:44:28 -0400894 handle, units, timeout,
895 acpi_format_exception(status)));
896 } else {
897 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
Thomas Renningera6fc6722006-06-26 23:58:43 -0400898 "Acquired semaphore[%p|%d|%d]", handle,
Len Brown4be44fc2005-08-05 00:44:28 -0400899 units, timeout));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 }
901
Patrick Mocheld550d982006-06-27 00:41:40 -0400902 return status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700903}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905/*
906 * TODO: Support for units > 1?
907 */
Len Brown4be44fc2005-08-05 00:44:28 -0400908acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909{
Len Brown4be44fc2005-08-05 00:44:28 -0400910 struct semaphore *sem = (struct semaphore *)handle;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 if (!sem || (units < 1))
Patrick Mocheld550d982006-06-27 00:41:40 -0400913 return AE_BAD_PARAMETER;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700914
915 if (units > 1)
Patrick Mocheld550d982006-06-27 00:41:40 -0400916 return AE_SUPPORT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917
Len Brown4be44fc2005-08-05 00:44:28 -0400918 ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Signaling semaphore[%p|%d]\n", handle,
919 units));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920
921 up(sem);
922
Patrick Mocheld550d982006-06-27 00:41:40 -0400923 return AE_OK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924}
Len Brown4be44fc2005-08-05 00:44:28 -0400925
Linus Torvalds1da177e2005-04-16 15:20:36 -0700926#ifdef ACPI_FUTURE_USAGE
Len Brown4be44fc2005-08-05 00:44:28 -0400927u32 acpi_os_get_line(char *buffer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700928{
929
930#ifdef ENABLE_DEBUGGER
931 if (acpi_in_debugger) {
932 u32 chars;
933
934 kdb_read(buffer, sizeof(line_buf));
935
936 /* remove the CR kdb includes */
937 chars = strlen(buffer) - 1;
938 buffer[chars] = '\0';
939 }
940#endif
941
942 return 0;
943}
Len Brown4be44fc2005-08-05 00:44:28 -0400944#endif /* ACPI_FUTURE_USAGE */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
Len Brown4be44fc2005-08-05 00:44:28 -0400946acpi_status acpi_os_signal(u32 function, void *info)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700947{
Len Brown4be44fc2005-08-05 00:44:28 -0400948 switch (function) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949 case ACPI_SIGNAL_FATAL:
950 printk(KERN_ERR PREFIX "Fatal opcode executed\n");
951 break;
952 case ACPI_SIGNAL_BREAKPOINT:
953 /*
954 * AML Breakpoint
955 * ACPI spec. says to treat it as a NOP unless
956 * you are debugging. So if/when we integrate
957 * AML debugger into the kernel debugger its
958 * hook will go here. But until then it is
959 * not useful to print anything on breakpoints.
960 */
961 break;
962 default:
963 break;
964 }
965
966 return AE_OK;
967}
Len Brown4be44fc2005-08-05 00:44:28 -0400968
Len Brown4be44fc2005-08-05 00:44:28 -0400969static int __init acpi_os_name_setup(char *str)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970{
971 char *p = acpi_os_name;
Len Brown4be44fc2005-08-05 00:44:28 -0400972 int count = ACPI_MAX_OVERRIDE_LEN - 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973
974 if (!str || !*str)
975 return 0;
976
977 for (; count-- && str && *str; str++) {
978 if (isalnum(*str) || *str == ' ' || *str == ':')
979 *p++ = *str;
980 else if (*str == '\'' || *str == '"')
981 continue;
982 else
983 break;
984 }
985 *p = 0;
986
987 return 1;
Len Brown4be44fc2005-08-05 00:44:28 -0400988
Linus Torvalds1da177e2005-04-16 15:20:36 -0700989}
990
991__setup("acpi_os_name=", acpi_os_name_setup);
992
Len Brownd4b7dc42008-01-23 20:50:56 -0500993static void __init set_osi_linux(unsigned int enable)
994{
995 if (osi_linux.enable != enable) {
996 osi_linux.enable = enable;
997 printk(KERN_NOTICE PREFIX "%sed _OSI(Linux)\n",
998 enable ? "Add": "Delet");
999 }
Lin Mingb0ed7a92010-08-06 09:35:51 +08001000
1001 if (osi_linux.enable)
1002 acpi_osi_setup("Linux");
1003 else
1004 acpi_osi_setup("!Linux");
1005
Len Brownd4b7dc42008-01-23 20:50:56 -05001006 return;
1007}
Len Brownf5076542007-05-30 00:10:38 -04001008
Len Brownd4b7dc42008-01-23 20:50:56 -05001009static void __init acpi_cmdline_osi_linux(unsigned int enable)
1010{
1011 osi_linux.cmdline = 1; /* cmdline set the default */
1012 set_osi_linux(enable);
Len Brownf5076542007-05-30 00:10:38 -04001013
Len Brownd4b7dc42008-01-23 20:50:56 -05001014 return;
1015}
1016
1017void __init acpi_dmi_osi_linux(int enable, const struct dmi_system_id *d)
1018{
1019 osi_linux.dmi = 1; /* DMI knows that this box asks OSI(Linux) */
1020
1021 printk(KERN_NOTICE PREFIX "DMI detected: %s\n", d->ident);
1022
1023 if (enable == -1)
1024 return;
1025
1026 osi_linux.known = 1; /* DMI knows which OSI(Linux) default needed */
1027
1028 set_osi_linux(enable);
1029
Len Brownf5076542007-05-30 00:10:38 -04001030 return;
1031}
1032
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033/*
Len Brownae00d812007-05-29 18:43:33 -04001034 * Modify the list of "OS Interfaces" reported to BIOS via _OSI
1035 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036 * empty string disables _OSI
Len Brownae00d812007-05-29 18:43:33 -04001037 * string starting with '!' disables that string
1038 * otherwise string is added to list, augmenting built-in strings
Linus Torvalds1da177e2005-04-16 15:20:36 -07001039 */
Lin Mingb0ed7a92010-08-06 09:35:51 +08001040static void __init acpi_osi_setup_late(void)
1041{
1042 char *str = osi_setup_string;
1043
1044 if (*str == '\0')
1045 return;
1046
1047 if (!strcmp("!Linux", str)) {
1048 acpi_cmdline_osi_linux(0); /* !enable */
1049 } else if (*str == '!') {
1050 if (acpi_remove_interface(++str) == AE_OK)
1051 printk(KERN_INFO PREFIX "Deleted _OSI(%s)\n", str);
1052 } else if (!strcmp("Linux", str)) {
1053 acpi_cmdline_osi_linux(1); /* enable */
1054 } else {
1055 if (acpi_install_interface(str) == AE_OK)
1056 printk(KERN_INFO PREFIX "Added _OSI(%s)\n", str);
1057 }
1058}
1059
Len Brown46c1fbd2008-02-13 23:13:25 -05001060int __init acpi_osi_setup(char *str)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061{
1062 if (str == NULL || *str == '\0') {
1063 printk(KERN_INFO PREFIX "_OSI method disabled\n");
1064 acpi_gbl_create_osi_method = FALSE;
Lin Mingb0ed7a92010-08-06 09:35:51 +08001065 } else {
1066 strncpy(osi_setup_string, str, OSI_STRING_LENGTH_MAX);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001067 }
1068
1069 return 1;
1070}
1071
1072__setup("acpi_osi=", acpi_osi_setup);
1073
1074/* enable serialization to combat AE_ALREADY_EXISTS errors */
Len Brown4be44fc2005-08-05 00:44:28 -04001075static int __init acpi_serialize_setup(char *str)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001076{
1077 printk(KERN_INFO PREFIX "serialize enabled\n");
1078
1079 acpi_gbl_all_methods_serialized = TRUE;
1080
1081 return 1;
1082}
1083
1084__setup("acpi_serialize", acpi_serialize_setup);
1085
Thomas Renningerdf92e692008-02-04 23:31:22 -08001086/* Check of resource interference between native drivers and ACPI
1087 * OperationRegions (SystemIO and System Memory only).
1088 * IO ports and memory declared in ACPI might be used by the ACPI subsystem
1089 * in arbitrary AML code and can interfere with legacy drivers.
1090 * acpi_enforce_resources= can be set to:
1091 *
Luca Tettamanti7e905602009-03-30 00:01:27 +02001092 * - strict (default) (2)
Thomas Renningerdf92e692008-02-04 23:31:22 -08001093 * -> further driver trying to access the resources will not load
Luca Tettamanti7e905602009-03-30 00:01:27 +02001094 * - lax (1)
Thomas Renningerdf92e692008-02-04 23:31:22 -08001095 * -> further driver trying to access the resources will load, but you
1096 * get a system message that something might go wrong...
1097 *
1098 * - no (0)
1099 * -> ACPI Operation Region resources will not be registered
1100 *
1101 */
1102#define ENFORCE_RESOURCES_STRICT 2
1103#define ENFORCE_RESOURCES_LAX 1
1104#define ENFORCE_RESOURCES_NO 0
1105
Luca Tettamanti7e905602009-03-30 00:01:27 +02001106static unsigned int acpi_enforce_resources = ENFORCE_RESOURCES_STRICT;
Thomas Renningerdf92e692008-02-04 23:31:22 -08001107
1108static int __init acpi_enforce_resources_setup(char *str)
1109{
1110 if (str == NULL || *str == '\0')
1111 return 0;
1112
1113 if (!strcmp("strict", str))
1114 acpi_enforce_resources = ENFORCE_RESOURCES_STRICT;
1115 else if (!strcmp("lax", str))
1116 acpi_enforce_resources = ENFORCE_RESOURCES_LAX;
1117 else if (!strcmp("no", str))
1118 acpi_enforce_resources = ENFORCE_RESOURCES_NO;
1119
1120 return 1;
1121}
1122
1123__setup("acpi_enforce_resources=", acpi_enforce_resources_setup);
1124
1125/* Check for resource conflicts between ACPI OperationRegions and native
1126 * drivers */
Jean Delvare876fba42009-11-11 15:22:15 +01001127int acpi_check_resource_conflict(const struct resource *res)
Thomas Renningerdf92e692008-02-04 23:31:22 -08001128{
1129 struct acpi_res_list *res_list_elem;
1130 int ioport;
1131 int clash = 0;
1132
1133 if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
1134 return 0;
1135 if (!(res->flags & IORESOURCE_IO) && !(res->flags & IORESOURCE_MEM))
1136 return 0;
1137
1138 ioport = res->flags & IORESOURCE_IO;
1139
1140 spin_lock(&acpi_res_lock);
1141 list_for_each_entry(res_list_elem, &resource_list_head,
1142 resource_list) {
1143 if (ioport && (res_list_elem->resource_type
1144 != ACPI_ADR_SPACE_SYSTEM_IO))
1145 continue;
1146 if (!ioport && (res_list_elem->resource_type
1147 != ACPI_ADR_SPACE_SYSTEM_MEMORY))
1148 continue;
1149
1150 if (res->end < res_list_elem->start
1151 || res_list_elem->end < res->start)
1152 continue;
1153 clash = 1;
1154 break;
1155 }
1156 spin_unlock(&acpi_res_lock);
1157
1158 if (clash) {
1159 if (acpi_enforce_resources != ENFORCE_RESOURCES_NO) {
Chase Douglas1638bca2010-03-22 15:08:09 -04001160 printk(KERN_WARNING "ACPI: resource %s %pR"
1161 " conflicts with ACPI region %s %pR\n",
1162 res->name, res, res_list_elem->name,
1163 res_list_elem);
Jean Delvare14f03342009-09-08 15:31:46 +02001164 if (acpi_enforce_resources == ENFORCE_RESOURCES_LAX)
1165 printk(KERN_NOTICE "ACPI: This conflict may"
1166 " cause random problems and system"
1167 " instability\n");
1168 printk(KERN_INFO "ACPI: If an ACPI driver is available"
1169 " for this device, you should use it instead of"
1170 " the native driver\n");
Thomas Renningerdf92e692008-02-04 23:31:22 -08001171 }
1172 if (acpi_enforce_resources == ENFORCE_RESOURCES_STRICT)
1173 return -EBUSY;
1174 }
1175 return 0;
1176}
Thomas Renninger443dea72008-02-04 23:31:23 -08001177EXPORT_SYMBOL(acpi_check_resource_conflict);
Thomas Renningerdf92e692008-02-04 23:31:22 -08001178
1179int acpi_check_region(resource_size_t start, resource_size_t n,
1180 const char *name)
1181{
1182 struct resource res = {
1183 .start = start,
1184 .end = start + n - 1,
1185 .name = name,
1186 .flags = IORESOURCE_IO,
1187 };
1188
1189 return acpi_check_resource_conflict(&res);
1190}
1191EXPORT_SYMBOL(acpi_check_region);
1192
1193int acpi_check_mem_region(resource_size_t start, resource_size_t n,
1194 const char *name)
1195{
1196 struct resource res = {
1197 .start = start,
1198 .end = start + n - 1,
1199 .name = name,
1200 .flags = IORESOURCE_MEM,
1201 };
1202
1203 return acpi_check_resource_conflict(&res);
1204
1205}
1206EXPORT_SYMBOL(acpi_check_mem_region);
1207
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208/*
Jean Delvare70dd6be2010-05-27 19:58:37 +02001209 * Let drivers know whether the resource checks are effective
1210 */
1211int acpi_resources_are_enforced(void)
1212{
1213 return acpi_enforce_resources == ENFORCE_RESOURCES_STRICT;
1214}
1215EXPORT_SYMBOL(acpi_resources_are_enforced);
1216
1217/*
Robert Moore73459f72005-06-24 00:00:00 -04001218 * Acquire a spinlock.
1219 *
1220 * handle is a pointer to the spinlock_t.
Robert Moore73459f72005-06-24 00:00:00 -04001221 */
1222
Bob Moore967440e32006-06-23 17:04:00 -04001223acpi_cpu_flags acpi_os_acquire_lock(acpi_spinlock lockp)
Robert Moore73459f72005-06-24 00:00:00 -04001224{
Bob Mooreb8e4d892006-01-27 16:43:00 -05001225 acpi_cpu_flags flags;
Bob Moore967440e32006-06-23 17:04:00 -04001226 spin_lock_irqsave(lockp, flags);
Robert Moore73459f72005-06-24 00:00:00 -04001227 return flags;
1228}
1229
1230/*
1231 * Release a spinlock. See above.
1232 */
1233
Bob Moore967440e32006-06-23 17:04:00 -04001234void acpi_os_release_lock(acpi_spinlock lockp, acpi_cpu_flags flags)
Robert Moore73459f72005-06-24 00:00:00 -04001235{
Bob Moore967440e32006-06-23 17:04:00 -04001236 spin_unlock_irqrestore(lockp, flags);
Robert Moore73459f72005-06-24 00:00:00 -04001237}
1238
Robert Moore73459f72005-06-24 00:00:00 -04001239#ifndef ACPI_USE_LOCAL_CACHE
1240
1241/*******************************************************************************
1242 *
1243 * FUNCTION: acpi_os_create_cache
1244 *
Bob Mooreb229cf92006-04-21 17:15:00 -04001245 * PARAMETERS: name - Ascii name for the cache
1246 * size - Size of each cached object
1247 * depth - Maximum depth of the cache (in objects) <ignored>
1248 * cache - Where the new cache object is returned
Robert Moore73459f72005-06-24 00:00:00 -04001249 *
Bob Mooreb229cf92006-04-21 17:15:00 -04001250 * RETURN: status
Robert Moore73459f72005-06-24 00:00:00 -04001251 *
1252 * DESCRIPTION: Create a cache object
1253 *
1254 ******************************************************************************/
1255
1256acpi_status
Len Brown4be44fc2005-08-05 00:44:28 -04001257acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache)
Robert Moore73459f72005-06-24 00:00:00 -04001258{
Paul Mundt20c2df82007-07-20 10:11:58 +09001259 *cache = kmem_cache_create(name, size, 0, 0, NULL);
Adrian Bunka6fdbf92006-12-19 12:56:13 -08001260 if (*cache == NULL)
Bob Mooreb229cf92006-04-21 17:15:00 -04001261 return AE_ERROR;
1262 else
1263 return AE_OK;
Robert Moore73459f72005-06-24 00:00:00 -04001264}
1265
1266/*******************************************************************************
1267 *
1268 * FUNCTION: acpi_os_purge_cache
1269 *
1270 * PARAMETERS: Cache - Handle to cache object
1271 *
1272 * RETURN: Status
1273 *
1274 * DESCRIPTION: Free all objects within the requested cache.
1275 *
1276 ******************************************************************************/
1277
Len Brown4be44fc2005-08-05 00:44:28 -04001278acpi_status acpi_os_purge_cache(acpi_cache_t * cache)
Robert Moore73459f72005-06-24 00:00:00 -04001279{
Jan Engelhardt50dd0962006-10-01 00:28:50 +02001280 kmem_cache_shrink(cache);
Len Brown4be44fc2005-08-05 00:44:28 -04001281 return (AE_OK);
Robert Moore73459f72005-06-24 00:00:00 -04001282}
1283
1284/*******************************************************************************
1285 *
1286 * FUNCTION: acpi_os_delete_cache
1287 *
1288 * PARAMETERS: Cache - Handle to cache object
1289 *
1290 * RETURN: Status
1291 *
1292 * DESCRIPTION: Free all objects within the requested cache and delete the
1293 * cache object.
1294 *
1295 ******************************************************************************/
1296
Len Brown4be44fc2005-08-05 00:44:28 -04001297acpi_status acpi_os_delete_cache(acpi_cache_t * cache)
Robert Moore73459f72005-06-24 00:00:00 -04001298{
Alexey Dobriyan1a1d92c2006-09-27 01:49:40 -07001299 kmem_cache_destroy(cache);
Len Brown4be44fc2005-08-05 00:44:28 -04001300 return (AE_OK);
Robert Moore73459f72005-06-24 00:00:00 -04001301}
1302
1303/*******************************************************************************
1304 *
1305 * FUNCTION: acpi_os_release_object
1306 *
1307 * PARAMETERS: Cache - Handle to cache object
1308 * Object - The object to be released
1309 *
1310 * RETURN: None
1311 *
1312 * DESCRIPTION: Release an object to the specified cache. If cache is full,
1313 * the object is deleted.
1314 *
1315 ******************************************************************************/
1316
Len Brown4be44fc2005-08-05 00:44:28 -04001317acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
Robert Moore73459f72005-06-24 00:00:00 -04001318{
Len Brown4be44fc2005-08-05 00:44:28 -04001319 kmem_cache_free(cache, object);
1320 return (AE_OK);
Robert Moore73459f72005-06-24 00:00:00 -04001321}
1322
Lin Minga5fe1a02009-08-13 10:43:27 +08001323static inline int acpi_res_list_add(struct acpi_res_list *res)
1324{
1325 struct acpi_res_list *res_list_elem;
1326
1327 list_for_each_entry(res_list_elem, &resource_list_head,
1328 resource_list) {
1329
1330 if (res->resource_type == res_list_elem->resource_type &&
1331 res->start == res_list_elem->start &&
1332 res->end == res_list_elem->end) {
1333
1334 /*
1335 * The Region(addr,len) already exist in the list,
1336 * just increase the count
1337 */
1338
1339 res_list_elem->count++;
1340 return 0;
1341 }
1342 }
1343
1344 res->count = 1;
1345 list_add(&res->resource_list, &resource_list_head);
1346 return 1;
1347}
1348
1349static inline void acpi_res_list_del(struct acpi_res_list *res)
1350{
1351 struct acpi_res_list *res_list_elem;
1352
1353 list_for_each_entry(res_list_elem, &resource_list_head,
1354 resource_list) {
1355
1356 if (res->resource_type == res_list_elem->resource_type &&
1357 res->start == res_list_elem->start &&
1358 res->end == res_list_elem->end) {
1359
1360 /*
1361 * If the res count is decreased to 0,
1362 * remove and free it
1363 */
1364
1365 if (--res_list_elem->count == 0) {
1366 list_del(&res_list_elem->resource_list);
1367 kfree(res_list_elem);
1368 }
1369 return;
1370 }
1371 }
1372}
1373
1374acpi_status
1375acpi_os_invalidate_address(
1376 u8 space_id,
1377 acpi_physical_address address,
1378 acpi_size length)
1379{
1380 struct acpi_res_list res;
1381
1382 switch (space_id) {
1383 case ACPI_ADR_SPACE_SYSTEM_IO:
1384 case ACPI_ADR_SPACE_SYSTEM_MEMORY:
Thomas Weber88393162010-03-16 11:47:56 +01001385 /* Only interference checks against SystemIO and SystemMemory
Lin Minga5fe1a02009-08-13 10:43:27 +08001386 are needed */
1387 res.start = address;
1388 res.end = address + length - 1;
1389 res.resource_type = space_id;
1390 spin_lock(&acpi_res_lock);
1391 acpi_res_list_del(&res);
1392 spin_unlock(&acpi_res_lock);
1393 break;
1394 case ACPI_ADR_SPACE_PCI_CONFIG:
1395 case ACPI_ADR_SPACE_EC:
1396 case ACPI_ADR_SPACE_SMBUS:
1397 case ACPI_ADR_SPACE_CMOS:
1398 case ACPI_ADR_SPACE_PCI_BAR_TARGET:
1399 case ACPI_ADR_SPACE_DATA_TABLE:
1400 case ACPI_ADR_SPACE_FIXED_HARDWARE:
1401 break;
1402 }
1403 return AE_OK;
1404}
1405
Bob Mooreb229cf92006-04-21 17:15:00 -04001406/******************************************************************************
1407 *
1408 * FUNCTION: acpi_os_validate_address
1409 *
1410 * PARAMETERS: space_id - ACPI space ID
1411 * address - Physical address
1412 * length - Address length
1413 *
1414 * RETURN: AE_OK if address/length is valid for the space_id. Otherwise,
1415 * should return AE_AML_ILLEGAL_ADDRESS.
1416 *
1417 * DESCRIPTION: Validate a system address via the host OS. Used to validate
1418 * the addresses accessed by AML operation regions.
1419 *
1420 *****************************************************************************/
1421
1422acpi_status
1423acpi_os_validate_address (
1424 u8 space_id,
1425 acpi_physical_address address,
Thomas Renningerdf92e692008-02-04 23:31:22 -08001426 acpi_size length,
1427 char *name)
Bob Mooreb229cf92006-04-21 17:15:00 -04001428{
Thomas Renningerdf92e692008-02-04 23:31:22 -08001429 struct acpi_res_list *res;
Lin Minga5fe1a02009-08-13 10:43:27 +08001430 int added;
Thomas Renningerdf92e692008-02-04 23:31:22 -08001431 if (acpi_enforce_resources == ENFORCE_RESOURCES_NO)
1432 return AE_OK;
Bob Mooreb229cf92006-04-21 17:15:00 -04001433
Thomas Renningerdf92e692008-02-04 23:31:22 -08001434 switch (space_id) {
1435 case ACPI_ADR_SPACE_SYSTEM_IO:
1436 case ACPI_ADR_SPACE_SYSTEM_MEMORY:
Thomas Weber88393162010-03-16 11:47:56 +01001437 /* Only interference checks against SystemIO and SystemMemory
Thomas Renningerdf92e692008-02-04 23:31:22 -08001438 are needed */
1439 res = kzalloc(sizeof(struct acpi_res_list), GFP_KERNEL);
1440 if (!res)
1441 return AE_OK;
1442 /* ACPI names are fixed to 4 bytes, still better use strlcpy */
1443 strlcpy(res->name, name, 5);
1444 res->start = address;
1445 res->end = address + length - 1;
1446 res->resource_type = space_id;
1447 spin_lock(&acpi_res_lock);
Lin Minga5fe1a02009-08-13 10:43:27 +08001448 added = acpi_res_list_add(res);
Thomas Renningerdf92e692008-02-04 23:31:22 -08001449 spin_unlock(&acpi_res_lock);
Lin Minga5fe1a02009-08-13 10:43:27 +08001450 pr_debug("%s %s resource: start: 0x%llx, end: 0x%llx, "
1451 "name: %s\n", added ? "Added" : "Already exist",
1452 (space_id == ACPI_ADR_SPACE_SYSTEM_IO)
Thomas Renningerdf92e692008-02-04 23:31:22 -08001453 ? "SystemIO" : "System Memory",
1454 (unsigned long long)res->start,
1455 (unsigned long long)res->end,
1456 res->name);
Lin Minga5fe1a02009-08-13 10:43:27 +08001457 if (!added)
1458 kfree(res);
Thomas Renningerdf92e692008-02-04 23:31:22 -08001459 break;
1460 case ACPI_ADR_SPACE_PCI_CONFIG:
1461 case ACPI_ADR_SPACE_EC:
1462 case ACPI_ADR_SPACE_SMBUS:
1463 case ACPI_ADR_SPACE_CMOS:
1464 case ACPI_ADR_SPACE_PCI_BAR_TARGET:
1465 case ACPI_ADR_SPACE_DATA_TABLE:
1466 case ACPI_ADR_SPACE_FIXED_HARDWARE:
1467 break;
1468 }
1469 return AE_OK;
Bob Mooreb229cf92006-04-21 17:15:00 -04001470}
1471
Robert Moore73459f72005-06-24 00:00:00 -04001472#endif