osl.c 24.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
/*
 *  acpi_osl.c - OS-dependent functions ($Revision: 83 $)
 *
 *  Copyright (C) 2000       Andrew Henroid
 *  Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
 *  Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 */

#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/pci.h>
#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kmod.h>
#include <linux/delay.h>
#include <linux/workqueue.h>
#include <linux/nmi.h>
#include <acpi/acpi.h>
#include <asm/io.h>
#include <acpi/acpi_bus.h>
#include <acpi/processor.h>
#include <asm/uaccess.h>

#include <linux/efi.h>

#define _COMPONENT		ACPI_OS_SERVICES
L
Len Brown 已提交
49
ACPI_MODULE_NAME("osl")
L
Linus Torvalds 已提交
50
#define PREFIX		"ACPI: "
L
Len Brown 已提交
51 52 53
struct acpi_os_dpc {
	acpi_osd_exec_callback function;
	void *context;
L
Linus Torvalds 已提交
54 55 56 57 58 59 60 61 62 63 64 65 66 67
};

#ifdef CONFIG_ACPI_CUSTOM_DSDT
#include CONFIG_ACPI_CUSTOM_DSDT_FILE
#endif

#ifdef ENABLE_DEBUGGER
#include <linux/kdb.h>

/* stuff for debugger support */
int acpi_in_debugger;
EXPORT_SYMBOL(acpi_in_debugger);

extern char line_buf[80];
L
Len Brown 已提交
68
#endif				/*ENABLE_DEBUGGER */
L
Linus Torvalds 已提交
69

70
int acpi_specific_hotkey_enabled = TRUE;
L
Luming Yu 已提交
71 72
EXPORT_SYMBOL(acpi_specific_hotkey_enabled);

L
Linus Torvalds 已提交
73 74 75 76 77
static unsigned int acpi_irq_irq;
static acpi_osd_handler acpi_irq_handler;
static void *acpi_irq_context;
static struct workqueue_struct *kacpid_wq;

L
Len Brown 已提交
78
acpi_status acpi_os_initialize(void)
L
Linus Torvalds 已提交
79 80 81 82
{
	return AE_OK;
}

L
Len Brown 已提交
83
acpi_status acpi_os_initialize1(void)
L
Linus Torvalds 已提交
84 85 86 87 88 89
{
	/*
	 * Initialize PCI configuration space access, as we'll need to access
	 * it while walking the namespace (bus 0 and root bridges w/ _BBNs).
	 */
	if (!raw_pci_ops) {
L
Len Brown 已提交
90 91
		printk(KERN_ERR PREFIX
		       "Access to PCI configuration space unavailable\n");
L
Linus Torvalds 已提交
92 93 94 95 96 97 98 99
		return AE_NULL_ENTRY;
	}
	kacpid_wq = create_singlethread_workqueue("kacpid");
	BUG_ON(!kacpid_wq);

	return AE_OK;
}

L
Len Brown 已提交
100
acpi_status acpi_os_terminate(void)
L
Linus Torvalds 已提交
101 102 103 104 105 106 107 108 109 110 111
{
	if (acpi_irq_handler) {
		acpi_os_remove_interrupt_handler(acpi_irq_irq,
						 acpi_irq_handler);
	}

	destroy_workqueue(kacpid_wq);

	return AE_OK;
}

L
Len Brown 已提交
112
void acpi_os_printf(const char *fmt, ...)
L
Linus Torvalds 已提交
113 114 115 116 117 118
{
	va_list args;
	va_start(args, fmt);
	acpi_os_vprintf(fmt, args);
	va_end(args);
}
L
Len Brown 已提交
119

L
Linus Torvalds 已提交
120 121
EXPORT_SYMBOL(acpi_os_printf);

L
Len Brown 已提交
122
void acpi_os_vprintf(const char *fmt, va_list args)
L
Linus Torvalds 已提交
123 124
{
	static char buffer[512];
L
Len Brown 已提交
125

L
Linus Torvalds 已提交
126 127 128 129 130 131 132 133 134 135 136 137 138
	vsprintf(buffer, fmt, args);

#ifdef ENABLE_DEBUGGER
	if (acpi_in_debugger) {
		kdb_printf("%s", buffer);
	} else {
		printk("%s", buffer);
	}
#else
	printk("%s", buffer);
#endif
}

139
extern int acpi_in_resume;
L
Len Brown 已提交
140
void *acpi_os_allocate(acpi_size size)
L
Linus Torvalds 已提交
141
{
142 143 144 145
	if (acpi_in_resume)
		return kmalloc(size, GFP_ATOMIC);
	else
		return kmalloc(size, GFP_KERNEL);
L
Linus Torvalds 已提交
146 147
}

L
Len Brown 已提交
148
void acpi_os_free(void *ptr)
L
Linus Torvalds 已提交
149 150 151
{
	kfree(ptr);
}
L
Len Brown 已提交
152

L
Linus Torvalds 已提交
153 154
EXPORT_SYMBOL(acpi_os_free);

L
Len Brown 已提交
155
acpi_status acpi_os_get_root_pointer(u32 flags, struct acpi_pointer *addr)
L
Linus Torvalds 已提交
156 157 158
{
	if (efi_enabled) {
		addr->pointer_type = ACPI_PHYSICAL_POINTER;
159 160 161 162
		if (efi.acpi20 != EFI_INVALID_TABLE_ADDR)
			addr->pointer.physical = efi.acpi20;
		else if (efi.acpi != EFI_INVALID_TABLE_ADDR)
			addr->pointer.physical = efi.acpi;
L
Linus Torvalds 已提交
163
		else {
L
Len Brown 已提交
164 165
			printk(KERN_ERR PREFIX
			       "System description tables not found\n");
L
Linus Torvalds 已提交
166 167 168 169
			return AE_NOT_FOUND;
		}
	} else {
		if (ACPI_FAILURE(acpi_find_root_pointer(flags, addr))) {
L
Len Brown 已提交
170 171
			printk(KERN_ERR PREFIX
			       "System description tables not found\n");
L
Linus Torvalds 已提交
172 173 174 175 176 177 178 179
			return AE_NOT_FOUND;
		}
	}

	return AE_OK;
}

acpi_status
L
Len Brown 已提交
180 181
acpi_os_map_memory(acpi_physical_address phys, acpi_size size,
		   void __iomem ** virt)
L
Linus Torvalds 已提交
182
{
183 184 185
	if (phys > ULONG_MAX) {
		printk(KERN_ERR PREFIX "Cannot map memory that high\n");
		return AE_BAD_PARAMETER;
L
Linus Torvalds 已提交
186
	}
187 188 189 190
	/*
	 * ioremap checks to ensure this is in reserved space
	 */
	*virt = ioremap((unsigned long)phys, size);
L
Linus Torvalds 已提交
191 192 193 194 195 196

	if (!*virt)
		return AE_NO_MEMORY;

	return AE_OK;
}
197
EXPORT_SYMBOL_GPL(acpi_os_map_memory);
L
Linus Torvalds 已提交
198

L
Len Brown 已提交
199
void acpi_os_unmap_memory(void __iomem * virt, acpi_size size)
L
Linus Torvalds 已提交
200 201 202
{
	iounmap(virt);
}
203
EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
L
Linus Torvalds 已提交
204 205 206

#ifdef ACPI_FUTURE_USAGE
acpi_status
L
Len Brown 已提交
207
acpi_os_get_physical_address(void *virt, acpi_physical_address * phys)
L
Linus Torvalds 已提交
208
{
L
Len Brown 已提交
209
	if (!phys || !virt)
L
Linus Torvalds 已提交
210 211 212 213 214 215 216 217 218 219 220 221 222
		return AE_BAD_PARAMETER;

	*phys = virt_to_phys(virt);

	return AE_OK;
}
#endif

#define ACPI_MAX_OVERRIDE_LEN 100

static char acpi_os_name[ACPI_MAX_OVERRIDE_LEN];

acpi_status
L
Len Brown 已提交
223 224
acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
			    acpi_string * new_val)
L
Linus Torvalds 已提交
225 226 227 228 229
{
	if (!init_val || !new_val)
		return AE_BAD_PARAMETER;

	*new_val = NULL;
L
Len Brown 已提交
230
	if (!memcmp(init_val->name, "_OS_", 4) && strlen(acpi_os_name)) {
L
Linus Torvalds 已提交
231
		printk(KERN_INFO PREFIX "Overriding _OS definition to '%s'\n",
L
Len Brown 已提交
232
		       acpi_os_name);
L
Linus Torvalds 已提交
233 234 235 236 237 238 239
		*new_val = acpi_os_name;
	}

	return AE_OK;
}

acpi_status
L
Len Brown 已提交
240 241
acpi_os_table_override(struct acpi_table_header * existing_table,
		       struct acpi_table_header ** new_table)
L
Linus Torvalds 已提交
242 243 244 245 246 247
{
	if (!existing_table || !new_table)
		return AE_BAD_PARAMETER;

#ifdef CONFIG_ACPI_CUSTOM_DSDT
	if (strncmp(existing_table->signature, "DSDT", 4) == 0)
L
Len Brown 已提交
248
		*new_table = (struct acpi_table_header *)AmlCode;
L
Linus Torvalds 已提交
249 250 251 252 253 254 255 256
	else
		*new_table = NULL;
#else
	*new_table = NULL;
#endif
	return AE_OK;
}

L
Len Brown 已提交
257
static irqreturn_t acpi_irq(int irq, void *dev_id, struct pt_regs *regs)
L
Linus Torvalds 已提交
258
{
L
Len Brown 已提交
259
	return (*acpi_irq_handler) (acpi_irq_context) ? IRQ_HANDLED : IRQ_NONE;
L
Linus Torvalds 已提交
260 261 262
}

acpi_status
L
Len Brown 已提交
263 264
acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
				  void *context)
L
Linus Torvalds 已提交
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
{
	unsigned int irq;

	/*
	 * 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.
	 */
	gsi = acpi_fadt.sci_int;
	if (acpi_gsi_to_irq(gsi, &irq) < 0) {
		printk(KERN_ERR PREFIX "SCI (ACPI GSI %d) not registered\n",
		       gsi);
		return AE_OK;
	}

	acpi_irq_handler = handler;
	acpi_irq_context = context;
	if (request_irq(irq, acpi_irq, SA_SHIRQ, "acpi", acpi_irq)) {
		printk(KERN_ERR PREFIX "SCI (IRQ%d) allocation failed\n", irq);
		return AE_NOT_ACQUIRED;
	}
	acpi_irq_irq = irq;

	return AE_OK;
}

L
Len Brown 已提交
291
acpi_status acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler)
L
Linus Torvalds 已提交
292 293 294 295 296 297 298 299 300 301 302 303 304 305
{
	if (irq) {
		free_irq(irq, acpi_irq);
		acpi_irq_handler = NULL;
		acpi_irq_irq = 0;
	}

	return AE_OK;
}

/*
 * Running in interpreter thread context, safe to sleep
 */

L
Len Brown 已提交
306
void acpi_os_sleep(acpi_integer ms)
L
Linus Torvalds 已提交
307
{
308
	schedule_timeout_interruptible(msecs_to_jiffies(ms));
L
Linus Torvalds 已提交
309
}
L
Len Brown 已提交
310

L
Linus Torvalds 已提交
311 312
EXPORT_SYMBOL(acpi_os_sleep);

L
Len Brown 已提交
313
void acpi_os_stall(u32 us)
L
Linus Torvalds 已提交
314 315 316 317 318 319 320 321 322 323 324
{
	while (us) {
		u32 delay = 1000;

		if (delay > us)
			delay = us;
		udelay(delay);
		touch_nmi_watchdog();
		us -= delay;
	}
}
L
Len Brown 已提交
325

L
Linus Torvalds 已提交
326 327 328 329 330 331 332
EXPORT_SYMBOL(acpi_os_stall);

/*
 * Support ACPI 3.0 AML Timer operand
 * Returns 64-bit free-running, monotonically increasing timer
 * with 100ns granularity
 */
L
Len Brown 已提交
333
u64 acpi_os_get_timer(void)
L
Linus Torvalds 已提交
334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
{
	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;
}

L
Len Brown 已提交
350
acpi_status acpi_os_read_port(acpi_io_address port, u32 * value, u32 width)
L
Linus Torvalds 已提交
351 352 353 354 355 356
{
	u32 dummy;

	if (!value)
		value = &dummy;

L
Len Brown 已提交
357
	switch (width) {
L
Linus Torvalds 已提交
358
	case 8:
L
Len Brown 已提交
359
		*(u8 *) value = inb(port);
L
Linus Torvalds 已提交
360 361
		break;
	case 16:
L
Len Brown 已提交
362
		*(u16 *) value = inw(port);
L
Linus Torvalds 已提交
363 364
		break;
	case 32:
L
Len Brown 已提交
365
		*(u32 *) value = inl(port);
L
Linus Torvalds 已提交
366 367 368 369 370 371 372
		break;
	default:
		BUG();
	}

	return AE_OK;
}
L
Len Brown 已提交
373

L
Linus Torvalds 已提交
374 375
EXPORT_SYMBOL(acpi_os_read_port);

L
Len Brown 已提交
376
acpi_status acpi_os_write_port(acpi_io_address port, u32 value, u32 width)
L
Linus Torvalds 已提交
377
{
L
Len Brown 已提交
378
	switch (width) {
L
Linus Torvalds 已提交
379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
	case 8:
		outb(value, port);
		break;
	case 16:
		outw(value, port);
		break;
	case 32:
		outl(value, port);
		break;
	default:
		BUG();
	}

	return AE_OK;
}
L
Len Brown 已提交
394

L
Linus Torvalds 已提交
395 396 397
EXPORT_SYMBOL(acpi_os_write_port);

acpi_status
L
Len Brown 已提交
398
acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
L
Linus Torvalds 已提交
399
{
L
Len Brown 已提交
400 401
	u32 dummy;
	void __iomem *virt_addr;
L
Linus Torvalds 已提交
402

403
	virt_addr = ioremap(phys_addr, width);
L
Linus Torvalds 已提交
404 405 406 407 408
	if (!value)
		value = &dummy;

	switch (width) {
	case 8:
L
Len Brown 已提交
409
		*(u8 *) value = readb(virt_addr);
L
Linus Torvalds 已提交
410 411
		break;
	case 16:
L
Len Brown 已提交
412
		*(u16 *) value = readw(virt_addr);
L
Linus Torvalds 已提交
413 414
		break;
	case 32:
L
Len Brown 已提交
415
		*(u32 *) value = readl(virt_addr);
L
Linus Torvalds 已提交
416 417 418 419 420
		break;
	default:
		BUG();
	}

421
	iounmap(virt_addr);
L
Linus Torvalds 已提交
422 423 424 425 426

	return AE_OK;
}

acpi_status
L
Len Brown 已提交
427
acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
L
Linus Torvalds 已提交
428
{
L
Len Brown 已提交
429
	void __iomem *virt_addr;
L
Linus Torvalds 已提交
430

431
	virt_addr = ioremap(phys_addr, width);
L
Linus Torvalds 已提交
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446

	switch (width) {
	case 8:
		writeb(value, virt_addr);
		break;
	case 16:
		writew(value, virt_addr);
		break;
	case 32:
		writel(value, virt_addr);
		break;
	default:
		BUG();
	}

447
	iounmap(virt_addr);
L
Linus Torvalds 已提交
448 449 450 451 452

	return AE_OK;
}

acpi_status
L
Len Brown 已提交
453 454
acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
			       void *value, u32 width)
L
Linus Torvalds 已提交
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
{
	int result, size;

	if (!value)
		return AE_BAD_PARAMETER;

	switch (width) {
	case 8:
		size = 1;
		break;
	case 16:
		size = 2;
		break;
	case 32:
		size = 4;
		break;
	default:
		return AE_ERROR;
	}

	BUG_ON(!raw_pci_ops);

	result = raw_pci_ops->read(pci_id->segment, pci_id->bus,
L
Len Brown 已提交
478 479
				   PCI_DEVFN(pci_id->device, pci_id->function),
				   reg, size, value);
L
Linus Torvalds 已提交
480 481 482

	return (result ? AE_ERROR : AE_OK);
}
L
Len Brown 已提交
483

L
Linus Torvalds 已提交
484 485 486
EXPORT_SYMBOL(acpi_os_read_pci_configuration);

acpi_status
L
Len Brown 已提交
487 488
acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
				acpi_integer value, u32 width)
L
Linus Torvalds 已提交
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508
{
	int result, size;

	switch (width) {
	case 8:
		size = 1;
		break;
	case 16:
		size = 2;
		break;
	case 32:
		size = 4;
		break;
	default:
		return AE_ERROR;
	}

	BUG_ON(!raw_pci_ops);

	result = raw_pci_ops->write(pci_id->segment, pci_id->bus,
L
Len Brown 已提交
509 510
				    PCI_DEVFN(pci_id->device, pci_id->function),
				    reg, size, value);
L
Linus Torvalds 已提交
511 512 513 514 515

	return (result ? AE_ERROR : AE_OK);
}

/* TODO: Change code to take advantage of driver model more */
L
Len Brown 已提交
516 517 518 519
static void acpi_os_derive_pci_id_2(acpi_handle rhandle,	/* upper bound  */
				    acpi_handle chandle,	/* current node */
				    struct acpi_pci_id **id,
				    int *is_bridge, u8 * bus_number)
L
Linus Torvalds 已提交
520
{
L
Len Brown 已提交
521 522 523 524 525 526
	acpi_handle handle;
	struct acpi_pci_id *pci_id = *id;
	acpi_status status;
	unsigned long temp;
	acpi_object_type type;
	u8 tu8;
L
Linus Torvalds 已提交
527 528 529

	acpi_get_parent(chandle, &handle);
	if (handle != rhandle) {
L
Len Brown 已提交
530 531
		acpi_os_derive_pci_id_2(rhandle, handle, &pci_id, is_bridge,
					bus_number);
L
Linus Torvalds 已提交
532 533

		status = acpi_get_type(handle, &type);
L
Len Brown 已提交
534
		if ((ACPI_FAILURE(status)) || (type != ACPI_TYPE_DEVICE))
L
Linus Torvalds 已提交
535 536
			return;

L
Len Brown 已提交
537 538 539
		status =
		    acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL,
					  &temp);
L
Linus Torvalds 已提交
540
		if (ACPI_SUCCESS(status)) {
L
Len Brown 已提交
541 542
			pci_id->device = ACPI_HIWORD(ACPI_LODWORD(temp));
			pci_id->function = ACPI_LOWORD(ACPI_LODWORD(temp));
L
Linus Torvalds 已提交
543 544 545 546 547

			if (*is_bridge)
				pci_id->bus = *bus_number;

			/* any nicer way to get bus number of bridge ? */
L
Len Brown 已提交
548 549 550 551 552 553 554 555
			status =
			    acpi_os_read_pci_configuration(pci_id, 0x0e, &tu8,
							   8);
			if (ACPI_SUCCESS(status)
			    && ((tu8 & 0x7f) == 1 || (tu8 & 0x7f) == 2)) {
				status =
				    acpi_os_read_pci_configuration(pci_id, 0x18,
								   &tu8, 8);
L
Linus Torvalds 已提交
556 557 558 559 560 561
				if (!ACPI_SUCCESS(status)) {
					/* Certainly broken...  FIX ME */
					return;
				}
				*is_bridge = 1;
				pci_id->bus = tu8;
L
Len Brown 已提交
562 563 564
				status =
				    acpi_os_read_pci_configuration(pci_id, 0x19,
								   &tu8, 8);
L
Linus Torvalds 已提交
565 566 567 568 569 570 571 572 573
				if (ACPI_SUCCESS(status)) {
					*bus_number = tu8;
				}
			} else
				*is_bridge = 0;
		}
	}
}

L
Len Brown 已提交
574 575 576
void acpi_os_derive_pci_id(acpi_handle rhandle,	/* upper bound  */
			   acpi_handle chandle,	/* current node */
			   struct acpi_pci_id **id)
L
Linus Torvalds 已提交
577 578 579 580 581 582 583
{
	int is_bridge = 1;
	u8 bus_number = (*id)->bus;

	acpi_os_derive_pci_id_2(rhandle, chandle, id, &is_bridge, &bus_number);
}

L
Len Brown 已提交
584
static void acpi_os_execute_deferred(void *context)
L
Linus Torvalds 已提交
585
{
L
Len Brown 已提交
586
	struct acpi_os_dpc *dpc = NULL;
L
Linus Torvalds 已提交
587

L
Len Brown 已提交
588
	ACPI_FUNCTION_TRACE("os_execute_deferred");
L
Linus Torvalds 已提交
589

L
Len Brown 已提交
590
	dpc = (struct acpi_os_dpc *)context;
L
Linus Torvalds 已提交
591
	if (!dpc) {
L
Len Brown 已提交
592
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid (NULL) context.\n"));
L
Linus Torvalds 已提交
593 594 595 596 597 598 599 600 601 602 603
		return_VOID;
	}

	dpc->function(dpc->context);

	kfree(dpc);

	return_VOID;
}

acpi_status
L
Len Brown 已提交
604 605
acpi_os_queue_for_execution(u32 priority,
			    acpi_osd_exec_callback function, void *context)
L
Linus Torvalds 已提交
606
{
L
Len Brown 已提交
607 608 609
	acpi_status status = AE_OK;
	struct acpi_os_dpc *dpc;
	struct work_struct *task;
L
Linus Torvalds 已提交
610

L
Len Brown 已提交
611
	ACPI_FUNCTION_TRACE("os_queue_for_execution");
L
Linus Torvalds 已提交
612

L
Len Brown 已提交
613 614 615
	ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
			  "Scheduling function [%p(%p)] for deferred execution.\n",
			  function, context));
L
Linus Torvalds 已提交
616 617

	if (!function)
L
Len Brown 已提交
618
		return_ACPI_STATUS(AE_BAD_PARAMETER);
L
Linus Torvalds 已提交
619 620 621 622 623 624 625 626 627 628 629 630

	/*
	 * Allocate/initialize DPC structure.  Note that this memory will be
	 * freed by the callee.  The kernel handles the tq_struct list  in a
	 * way that allows us to also free its memory inside the callee.
	 * Because we may want to schedule several tasks with different
	 * parameters we can't use the approach some kernel code uses of
	 * having a static tq_struct.
	 * We can save time and code by allocating the DPC and tq_structs
	 * from the same memory.
	 */

L
Len Brown 已提交
631 632 633
	dpc =
	    kmalloc(sizeof(struct acpi_os_dpc) + sizeof(struct work_struct),
		    GFP_ATOMIC);
L
Linus Torvalds 已提交
634
	if (!dpc)
L
Len Brown 已提交
635
		return_ACPI_STATUS(AE_NO_MEMORY);
L
Linus Torvalds 已提交
636 637 638 639

	dpc->function = function;
	dpc->context = context;

L
Len Brown 已提交
640 641
	task = (void *)(dpc + 1);
	INIT_WORK(task, acpi_os_execute_deferred, (void *)dpc);
L
Linus Torvalds 已提交
642 643

	if (!queue_work(kacpid_wq, task)) {
L
Len Brown 已提交
644 645
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "Call to queue_work() failed.\n"));
L
Linus Torvalds 已提交
646 647 648 649
		kfree(dpc);
		status = AE_ERROR;
	}

L
Len Brown 已提交
650
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
651
}
L
Len Brown 已提交
652

L
Linus Torvalds 已提交
653 654
EXPORT_SYMBOL(acpi_os_queue_for_execution);

L
Len Brown 已提交
655
void acpi_os_wait_events_complete(void *context)
L
Linus Torvalds 已提交
656 657 658
{
	flush_workqueue(kacpid_wq);
}
L
Len Brown 已提交
659

L
Linus Torvalds 已提交
660 661 662 663 664
EXPORT_SYMBOL(acpi_os_wait_events_complete);

/*
 * Allocate the memory for a spinlock and initialize it.
 */
L
Len Brown 已提交
665
acpi_status acpi_os_create_lock(acpi_handle * out_handle)
L
Linus Torvalds 已提交
666 667 668
{
	spinlock_t *lock_ptr;

L
Len Brown 已提交
669
	ACPI_FUNCTION_TRACE("os_create_lock");
L
Linus Torvalds 已提交
670 671 672 673 674

	lock_ptr = acpi_os_allocate(sizeof(spinlock_t));

	spin_lock_init(lock_ptr);

L
Len Brown 已提交
675
	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Creating spinlock[%p].\n", lock_ptr));
L
Linus Torvalds 已提交
676 677 678

	*out_handle = lock_ptr;

L
Len Brown 已提交
679
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
680 681 682 683 684
}

/*
 * Deallocate the memory for a spinlock.
 */
L
Len Brown 已提交
685
void acpi_os_delete_lock(acpi_handle handle)
L
Linus Torvalds 已提交
686
{
L
Len Brown 已提交
687
	ACPI_FUNCTION_TRACE("os_create_lock");
L
Linus Torvalds 已提交
688

L
Len Brown 已提交
689
	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Deleting spinlock[%p].\n", handle));
L
Linus Torvalds 已提交
690 691 692 693 694 695 696

	acpi_os_free(handle);

	return_VOID;
}

acpi_status
L
Len Brown 已提交
697
acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle)
L
Linus Torvalds 已提交
698
{
L
Len Brown 已提交
699
	struct semaphore *sem = NULL;
L
Linus Torvalds 已提交
700

L
Len Brown 已提交
701
	ACPI_FUNCTION_TRACE("os_create_semaphore");
L
Linus Torvalds 已提交
702 703 704

	sem = acpi_os_allocate(sizeof(struct semaphore));
	if (!sem)
L
Len Brown 已提交
705
		return_ACPI_STATUS(AE_NO_MEMORY);
L
Linus Torvalds 已提交
706 707 708 709
	memset(sem, 0, sizeof(struct semaphore));

	sema_init(sem, initial_units);

L
Len Brown 已提交
710
	*handle = (acpi_handle *) sem;
L
Linus Torvalds 已提交
711

L
Len Brown 已提交
712 713
	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Creating semaphore[%p|%d].\n",
			  *handle, initial_units));
L
Linus Torvalds 已提交
714

L
Len Brown 已提交
715
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
716 717
}

L
Len Brown 已提交
718
EXPORT_SYMBOL(acpi_os_create_semaphore);
L
Linus Torvalds 已提交
719 720 721 722 723 724 725 726

/*
 * TODO: A better way to delete semaphores?  Linux doesn't have a
 * 'delete_semaphore()' function -- may result in an invalid
 * pointer dereference for non-synchronized consumers.	Should
 * we at least check for blocked threads and signal/cancel them?
 */

L
Len Brown 已提交
727
acpi_status acpi_os_delete_semaphore(acpi_handle handle)
L
Linus Torvalds 已提交
728
{
L
Len Brown 已提交
729
	struct semaphore *sem = (struct semaphore *)handle;
L
Linus Torvalds 已提交
730

L
Len Brown 已提交
731
	ACPI_FUNCTION_TRACE("os_delete_semaphore");
L
Linus Torvalds 已提交
732 733

	if (!sem)
L
Len Brown 已提交
734
		return_ACPI_STATUS(AE_BAD_PARAMETER);
L
Linus Torvalds 已提交
735

L
Len Brown 已提交
736
	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Deleting semaphore[%p].\n", handle));
L
Linus Torvalds 已提交
737

L
Len Brown 已提交
738 739
	acpi_os_free(sem);
	sem = NULL;
L
Linus Torvalds 已提交
740

L
Len Brown 已提交
741
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
742 743
}

L
Len Brown 已提交
744
EXPORT_SYMBOL(acpi_os_delete_semaphore);
L
Linus Torvalds 已提交
745 746 747 748 749 750 751 752 753 754

/*
 * TODO: The kernel doesn't have a 'down_timeout' function -- had to
 * improvise.  The process is to sleep for one scheduler quantum
 * until the semaphore becomes available.  Downside is that this
 * may result in starvation for timeout-based waits when there's
 * lots of semaphore activity.
 *
 * TODO: Support for units > 1?
 */
L
Len Brown 已提交
755
acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout)
L
Linus Torvalds 已提交
756
{
L
Len Brown 已提交
757 758 759
	acpi_status status = AE_OK;
	struct semaphore *sem = (struct semaphore *)handle;
	int ret = 0;
L
Linus Torvalds 已提交
760

L
Len Brown 已提交
761
	ACPI_FUNCTION_TRACE("os_wait_semaphore");
L
Linus Torvalds 已提交
762 763

	if (!sem || (units < 1))
L
Len Brown 已提交
764
		return_ACPI_STATUS(AE_BAD_PARAMETER);
L
Linus Torvalds 已提交
765 766

	if (units > 1)
L
Len Brown 已提交
767
		return_ACPI_STATUS(AE_SUPPORT);
L
Linus Torvalds 已提交
768

L
Len Brown 已提交
769 770
	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Waiting for semaphore[%p|%d|%d]\n",
			  handle, units, timeout));
L
Linus Torvalds 已提交
771 772 773 774

	if (in_atomic())
		timeout = 0;

L
Len Brown 已提交
775
	switch (timeout) {
L
Linus Torvalds 已提交
776 777 778 779 780 781 782
		/*
		 * No Wait:
		 * --------
		 * A zero timeout value indicates that we shouldn't wait - just
		 * acquire the semaphore if available otherwise return AE_TIME
		 * (a.k.a. 'would block').
		 */
L
Len Brown 已提交
783 784
	case 0:
		if (down_trylock(sem))
L
Linus Torvalds 已提交
785 786 787 788 789 790 791
			status = AE_TIME;
		break;

		/*
		 * Wait Indefinitely:
		 * ------------------
		 */
L
Len Brown 已提交
792
	case ACPI_WAIT_FOREVER:
L
Linus Torvalds 已提交
793 794 795 796 797 798 799
		down(sem);
		break;

		/*
		 * Wait w/ Timeout:
		 * ----------------
		 */
L
Len Brown 已提交
800
	default:
L
Linus Torvalds 已提交
801 802 803
		// TODO: A better timeout algorithm?
		{
			int i = 0;
L
Len Brown 已提交
804
			static const int quantum_ms = 1000 / HZ;
L
Linus Torvalds 已提交
805 806

			ret = down_trylock(sem);
807
			for (i = timeout; (i > 0 && ret != 0); i -= quantum_ms) {
808
				schedule_timeout_interruptible(1);
L
Linus Torvalds 已提交
809 810
				ret = down_trylock(sem);
			}
L
Len Brown 已提交
811

L
Linus Torvalds 已提交
812 813 814 815 816 817 818
			if (ret != 0)
				status = AE_TIME;
		}
		break;
	}

	if (ACPI_FAILURE(status)) {
L
Len Brown 已提交
819 820 821 822 823 824 825 826
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "Failed to acquire semaphore[%p|%d|%d], %s\n",
				  handle, units, timeout,
				  acpi_format_exception(status)));
	} else {
		ACPI_DEBUG_PRINT((ACPI_DB_MUTEX,
				  "Acquired semaphore[%p|%d|%d]\n", handle,
				  units, timeout));
L
Linus Torvalds 已提交
827 828
	}

L
Len Brown 已提交
829
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
830 831
}

L
Len Brown 已提交
832
EXPORT_SYMBOL(acpi_os_wait_semaphore);
L
Linus Torvalds 已提交
833 834 835 836

/*
 * TODO: Support for units > 1?
 */
L
Len Brown 已提交
837
acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units)
L
Linus Torvalds 已提交
838
{
L
Len Brown 已提交
839
	struct semaphore *sem = (struct semaphore *)handle;
L
Linus Torvalds 已提交
840

L
Len Brown 已提交
841
	ACPI_FUNCTION_TRACE("os_signal_semaphore");
L
Linus Torvalds 已提交
842 843

	if (!sem || (units < 1))
L
Len Brown 已提交
844
		return_ACPI_STATUS(AE_BAD_PARAMETER);
L
Linus Torvalds 已提交
845 846

	if (units > 1)
L
Len Brown 已提交
847
		return_ACPI_STATUS(AE_SUPPORT);
L
Linus Torvalds 已提交
848

L
Len Brown 已提交
849 850
	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Signaling semaphore[%p|%d]\n", handle,
			  units));
L
Linus Torvalds 已提交
851 852 853

	up(sem);

L
Len Brown 已提交
854
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
855
}
L
Len Brown 已提交
856

L
Linus Torvalds 已提交
857 858 859
EXPORT_SYMBOL(acpi_os_signal_semaphore);

#ifdef ACPI_FUTURE_USAGE
L
Len Brown 已提交
860
u32 acpi_os_get_line(char *buffer)
L
Linus Torvalds 已提交
861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876
{

#ifdef ENABLE_DEBUGGER
	if (acpi_in_debugger) {
		u32 chars;

		kdb_read(buffer, sizeof(line_buf));

		/* remove the CR kdb includes */
		chars = strlen(buffer) - 1;
		buffer[chars] = '\0';
	}
#endif

	return 0;
}
L
Len Brown 已提交
877
#endif				/*  ACPI_FUTURE_USAGE  */
L
Linus Torvalds 已提交
878 879

/* Assumes no unreadable holes inbetween */
L
Len Brown 已提交
880
u8 acpi_os_readable(void *ptr, acpi_size len)
L
Linus Torvalds 已提交
881
{
L
Len Brown 已提交
882
#if defined(__i386__) || defined(__x86_64__)
L
Linus Torvalds 已提交
883
	char tmp;
L
Len Brown 已提交
884 885
	return !__get_user(tmp, (char __user *)ptr)
	    && !__get_user(tmp, (char __user *)ptr + len - 1);
L
Linus Torvalds 已提交
886 887 888 889 890
#endif
	return 1;
}

#ifdef ACPI_FUTURE_USAGE
L
Len Brown 已提交
891
u8 acpi_os_writable(void *ptr, acpi_size len)
L
Linus Torvalds 已提交
892 893 894 895 896 897 898
{
	/* could do dummy write (racy) or a kernel page table lookup.
	   The later may be difficult at early boot when kmap doesn't work yet. */
	return 1;
}
#endif

L
Len Brown 已提交
899
acpi_status acpi_os_signal(u32 function, void *info)
L
Linus Torvalds 已提交
900
{
L
Len Brown 已提交
901
	switch (function) {
L
Linus Torvalds 已提交
902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920
	case ACPI_SIGNAL_FATAL:
		printk(KERN_ERR PREFIX "Fatal opcode executed\n");
		break;
	case ACPI_SIGNAL_BREAKPOINT:
		/*
		 * AML Breakpoint
		 * ACPI spec. says to treat it as a NOP unless
		 * you are debugging.  So if/when we integrate
		 * AML debugger into the kernel debugger its
		 * hook will go here.  But until then it is
		 * not useful to print anything on breakpoints.
		 */
		break;
	default:
		break;
	}

	return AE_OK;
}
L
Len Brown 已提交
921

L
Linus Torvalds 已提交
922 923
EXPORT_SYMBOL(acpi_os_signal);

L
Len Brown 已提交
924
static int __init acpi_os_name_setup(char *str)
L
Linus Torvalds 已提交
925 926
{
	char *p = acpi_os_name;
L
Len Brown 已提交
927
	int count = ACPI_MAX_OVERRIDE_LEN - 1;
L
Linus Torvalds 已提交
928 929 930 931 932 933 934 935 936 937 938 939 940 941 942

	if (!str || !*str)
		return 0;

	for (; count-- && str && *str; str++) {
		if (isalnum(*str) || *str == ' ' || *str == ':')
			*p++ = *str;
		else if (*str == '\'' || *str == '"')
			continue;
		else
			break;
	}
	*p = 0;

	return 1;
L
Len Brown 已提交
943

L
Linus Torvalds 已提交
944 945 946 947 948 949 950 951 952
}

__setup("acpi_os_name=", acpi_os_name_setup);

/*
 * _OSI control
 * empty string disables _OSI
 * TBD additional string adds to _OSI
 */
L
Len Brown 已提交
953
static int __init acpi_osi_setup(char *str)
L
Linus Torvalds 已提交
954 955 956 957
{
	if (str == NULL || *str == '\0') {
		printk(KERN_INFO PREFIX "_OSI method disabled\n");
		acpi_gbl_create_osi_method = FALSE;
L
Len Brown 已提交
958
	} else {
L
Linus Torvalds 已提交
959
		/* TBD */
L
Len Brown 已提交
960 961
		printk(KERN_ERR PREFIX "_OSI additional string ignored -- %s\n",
		       str);
L
Linus Torvalds 已提交
962 963 964 965 966 967 968 969
	}

	return 1;
}

__setup("acpi_osi=", acpi_osi_setup);

/* enable serialization to combat AE_ALREADY_EXISTS errors */
L
Len Brown 已提交
970
static int __init acpi_serialize_setup(char *str)
L
Linus Torvalds 已提交
971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989
{
	printk(KERN_INFO PREFIX "serialize enabled\n");

	acpi_gbl_all_methods_serialized = TRUE;

	return 1;
}

__setup("acpi_serialize", acpi_serialize_setup);

/*
 * Wake and Run-Time GPES are expected to be separate.
 * We disable wake-GPEs at run-time to prevent spurious
 * interrupts.
 *
 * However, if a system exists that shares Wake and
 * Run-time events on the same GPE this flag is available
 * to tell Linux to keep the wake-time GPEs enabled at run-time.
 */
L
Len Brown 已提交
990
static int __init acpi_wake_gpes_always_on_setup(char *str)
L
Linus Torvalds 已提交
991 992 993 994 995 996 997 998 999 1000
{
	printk(KERN_INFO PREFIX "wake GPEs not disabled\n");

	acpi_gbl_leave_wake_gpes_disabled = FALSE;

	return 1;
}

__setup("acpi_wake_gpes_always_on", acpi_wake_gpes_always_on_setup);

1001
static int __init acpi_hotkey_setup(char *str)
L
Luming Yu 已提交
1002
{
1003
	acpi_specific_hotkey_enabled = FALSE;
L
Luming Yu 已提交
1004 1005 1006
	return 1;
}

1007
__setup("acpi_generic_hotkey", acpi_hotkey_setup);
L
Luming Yu 已提交
1008

L
Linus Torvalds 已提交
1009 1010 1011 1012 1013 1014 1015
/*
 * max_cstate is defined in the base kernel so modules can
 * change it w/o depending on the state of the processor module.
 */
unsigned int max_cstate = ACPI_PROCESSOR_MAX_POWER;

EXPORT_SYMBOL(max_cstate);
1016 1017 1018 1019 1020 1021 1022

/*
 * Acquire a spinlock.
 *
 * handle is a pointer to the spinlock_t.
 */

B
Bob Moore 已提交
1023
acpi_cpu_flags acpi_os_acquire_lock(acpi_handle handle)
1024
{
B
Bob Moore 已提交
1025
	acpi_cpu_flags flags;
L
Len Brown 已提交
1026
	spin_lock_irqsave((spinlock_t *) handle, flags);
1027 1028 1029 1030 1031 1032 1033
	return flags;
}

/*
 * Release a spinlock. See above.
 */

B
Bob Moore 已提交
1034
void acpi_os_release_lock(acpi_handle handle, acpi_cpu_flags flags)
1035
{
B
Bob Moore 已提交
1036
	spin_unlock_irqrestore((spinlock_t *) handle, flags);
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056
}

#ifndef ACPI_USE_LOCAL_CACHE

/*******************************************************************************
 *
 * FUNCTION:    acpi_os_create_cache
 *
 * PARAMETERS:  CacheName       - Ascii name for the cache
 *              ObjectSize      - Size of each cached object
 *              MaxDepth        - Maximum depth of the cache (in objects)
 *              ReturnCache     - Where the new cache object is returned
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Create a cache object
 *
 ******************************************************************************/

acpi_status
L
Len Brown 已提交
1057
acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache)
1058
{
L
Len Brown 已提交
1059
	*cache = kmem_cache_create(name, size, 0, 0, NULL, NULL);
1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074
	return AE_OK;
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_os_purge_cache
 *
 * PARAMETERS:  Cache           - Handle to cache object
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Free all objects within the requested cache.
 *
 ******************************************************************************/

L
Len Brown 已提交
1075
acpi_status acpi_os_purge_cache(acpi_cache_t * cache)
1076
{
L
Len Brown 已提交
1077 1078
	(void)kmem_cache_shrink(cache);
	return (AE_OK);
1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_os_delete_cache
 *
 * PARAMETERS:  Cache           - Handle to cache object
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Free all objects within the requested cache and delete the
 *              cache object.
 *
 ******************************************************************************/

L
Len Brown 已提交
1094
acpi_status acpi_os_delete_cache(acpi_cache_t * cache)
1095
{
L
Len Brown 已提交
1096 1097
	(void)kmem_cache_destroy(cache);
	return (AE_OK);
1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_os_release_object
 *
 * PARAMETERS:  Cache       - Handle to cache object
 *              Object      - The object to be released
 *
 * RETURN:      None
 *
 * DESCRIPTION: Release an object to the specified cache.  If cache is full,
 *              the object is deleted.
 *
 ******************************************************************************/

L
Len Brown 已提交
1114
acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
1115
{
L
Len Brown 已提交
1116 1117
	kmem_cache_free(cache, object);
	return (AE_OK);
1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_os_acquire_object
 *
 * PARAMETERS:  Cache           - Handle to cache object
 *              ReturnObject    - Where the object is returned
 *
 * RETURN:      Status
 *
 * DESCRIPTION: Get an object from the specified cache.  If cache is empty,
 *              the object is allocated.
 *
 ******************************************************************************/

L
Len Brown 已提交
1134
void *acpi_os_acquire_object(acpi_cache_t * cache)
1135
{
L
Len Brown 已提交
1136 1137 1138
	void *object = kmem_cache_alloc(cache, GFP_KERNEL);
	WARN_ON(!object);
	return object;
1139 1140 1141
}

#endif