osl.c 25.3 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 159 160
{
	if (efi_enabled) {
		addr->pointer_type = ACPI_PHYSICAL_POINTER;
		if (efi.acpi20)
			addr->pointer.physical =
L
Len Brown 已提交
161
			    (acpi_physical_address) virt_to_phys(efi.acpi20);
L
Linus Torvalds 已提交
162 163
		else if (efi.acpi)
			addr->pointer.physical =
L
Len Brown 已提交
164
			    (acpi_physical_address) virt_to_phys(efi.acpi);
L
Linus Torvalds 已提交
165
		else {
L
Len Brown 已提交
166 167
			printk(KERN_ERR PREFIX
			       "System description tables not found\n");
L
Linus Torvalds 已提交
168 169 170 171
			return AE_NOT_FOUND;
		}
	} else {
		if (ACPI_FAILURE(acpi_find_root_pointer(flags, addr))) {
L
Len Brown 已提交
172 173
			printk(KERN_ERR PREFIX
			       "System description tables not found\n");
L
Linus Torvalds 已提交
174 175 176 177 178 179 180 181
			return AE_NOT_FOUND;
		}
	}

	return AE_OK;
}

acpi_status
L
Len Brown 已提交
182 183
acpi_os_map_memory(acpi_physical_address phys, acpi_size size,
		   void __iomem ** virt)
L
Linus Torvalds 已提交
184 185 186
{
	if (efi_enabled) {
		if (EFI_MEMORY_WB & efi_mem_attributes(phys)) {
L
Len Brown 已提交
187
			*virt = (void __iomem *)phys_to_virt(phys);
L
Linus Torvalds 已提交
188 189 190 191 192 193 194 195 196
		} else {
			*virt = ioremap(phys, size);
		}
	} else {
		if (phys > ULONG_MAX) {
			printk(KERN_ERR PREFIX "Cannot map memory that high\n");
			return AE_BAD_PARAMETER;
		}
		/*
L
Len Brown 已提交
197 198 199
		 * ioremap checks to ensure this is in reserved space
		 */
		*virt = ioremap((unsigned long)phys, size);
L
Linus Torvalds 已提交
200 201 202 203 204 205 206 207
	}

	if (!*virt)
		return AE_NO_MEMORY;

	return AE_OK;
}

L
Len Brown 已提交
208
void acpi_os_unmap_memory(void __iomem * virt, acpi_size size)
L
Linus Torvalds 已提交
209 210 211 212 213 214
{
	iounmap(virt);
}

#ifdef ACPI_FUTURE_USAGE
acpi_status
L
Len Brown 已提交
215
acpi_os_get_physical_address(void *virt, acpi_physical_address * phys)
L
Linus Torvalds 已提交
216
{
L
Len Brown 已提交
217
	if (!phys || !virt)
L
Linus Torvalds 已提交
218 219 220 221 222 223 224 225 226 227 228 229 230
		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 已提交
231 232
acpi_os_predefined_override(const struct acpi_predefined_names *init_val,
			    acpi_string * new_val)
L
Linus Torvalds 已提交
233 234 235 236 237
{
	if (!init_val || !new_val)
		return AE_BAD_PARAMETER;

	*new_val = NULL;
L
Len Brown 已提交
238
	if (!memcmp(init_val->name, "_OS_", 4) && strlen(acpi_os_name)) {
L
Linus Torvalds 已提交
239
		printk(KERN_INFO PREFIX "Overriding _OS definition to '%s'\n",
L
Len Brown 已提交
240
		       acpi_os_name);
L
Linus Torvalds 已提交
241 242 243 244 245 246 247
		*new_val = acpi_os_name;
	}

	return AE_OK;
}

acpi_status
L
Len Brown 已提交
248 249
acpi_os_table_override(struct acpi_table_header * existing_table,
		       struct acpi_table_header ** new_table)
L
Linus Torvalds 已提交
250 251 252 253 254 255
{
	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 已提交
256
		*new_table = (struct acpi_table_header *)AmlCode;
L
Linus Torvalds 已提交
257 258 259 260 261 262 263 264
	else
		*new_table = NULL;
#else
	*new_table = NULL;
#endif
	return AE_OK;
}

L
Len Brown 已提交
265
static irqreturn_t acpi_irq(int irq, void *dev_id, struct pt_regs *regs)
L
Linus Torvalds 已提交
266
{
L
Len Brown 已提交
267
	return (*acpi_irq_handler) (acpi_irq_context) ? IRQ_HANDLED : IRQ_NONE;
L
Linus Torvalds 已提交
268 269 270
}

acpi_status
L
Len Brown 已提交
271 272
acpi_os_install_interrupt_handler(u32 gsi, acpi_osd_handler handler,
				  void *context)
L
Linus Torvalds 已提交
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
{
	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 已提交
299
acpi_status acpi_os_remove_interrupt_handler(u32 irq, acpi_osd_handler handler)
L
Linus Torvalds 已提交
300 301 302 303 304 305 306 307 308 309 310 311 312 313
{
	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 已提交
314
void acpi_os_sleep(acpi_integer ms)
L
Linus Torvalds 已提交
315
{
316
	schedule_timeout_interruptible(msecs_to_jiffies(ms));
L
Linus Torvalds 已提交
317
}
L
Len Brown 已提交
318

L
Linus Torvalds 已提交
319 320
EXPORT_SYMBOL(acpi_os_sleep);

L
Len Brown 已提交
321
void acpi_os_stall(u32 us)
L
Linus Torvalds 已提交
322 323 324 325 326 327 328 329 330 331 332
{
	while (us) {
		u32 delay = 1000;

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

L
Linus Torvalds 已提交
334 335 336 337 338 339 340
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 已提交
341
u64 acpi_os_get_timer(void)
L
Linus Torvalds 已提交
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357
{
	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 已提交
358
acpi_status acpi_os_read_port(acpi_io_address port, u32 * value, u32 width)
L
Linus Torvalds 已提交
359 360 361 362 363 364
{
	u32 dummy;

	if (!value)
		value = &dummy;

L
Len Brown 已提交
365
	switch (width) {
L
Linus Torvalds 已提交
366
	case 8:
L
Len Brown 已提交
367
		*(u8 *) value = inb(port);
L
Linus Torvalds 已提交
368 369
		break;
	case 16:
L
Len Brown 已提交
370
		*(u16 *) value = inw(port);
L
Linus Torvalds 已提交
371 372
		break;
	case 32:
L
Len Brown 已提交
373
		*(u32 *) value = inl(port);
L
Linus Torvalds 已提交
374 375 376 377 378 379 380
		break;
	default:
		BUG();
	}

	return AE_OK;
}
L
Len Brown 已提交
381

L
Linus Torvalds 已提交
382 383
EXPORT_SYMBOL(acpi_os_read_port);

L
Len Brown 已提交
384
acpi_status acpi_os_write_port(acpi_io_address port, u32 value, u32 width)
L
Linus Torvalds 已提交
385
{
L
Len Brown 已提交
386
	switch (width) {
L
Linus Torvalds 已提交
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401
	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 已提交
402

L
Linus Torvalds 已提交
403 404 405
EXPORT_SYMBOL(acpi_os_write_port);

acpi_status
L
Len Brown 已提交
406
acpi_os_read_memory(acpi_physical_address phys_addr, u32 * value, u32 width)
L
Linus Torvalds 已提交
407
{
L
Len Brown 已提交
408 409 410
	u32 dummy;
	void __iomem *virt_addr;
	int iomem = 0;
L
Linus Torvalds 已提交
411 412 413 414

	if (efi_enabled) {
		if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) {
			/* HACK ALERT! We can use readb/w/l on real memory too.. */
L
Len Brown 已提交
415
			virt_addr = (void __iomem *)phys_to_virt(phys_addr);
L
Linus Torvalds 已提交
416 417 418 419 420
		} else {
			iomem = 1;
			virt_addr = ioremap(phys_addr, width);
		}
	} else
L
Len Brown 已提交
421
		virt_addr = (void __iomem *)phys_to_virt(phys_addr);
L
Linus Torvalds 已提交
422 423 424 425 426
	if (!value)
		value = &dummy;

	switch (width) {
	case 8:
L
Len Brown 已提交
427
		*(u8 *) value = readb(virt_addr);
L
Linus Torvalds 已提交
428 429
		break;
	case 16:
L
Len Brown 已提交
430
		*(u16 *) value = readw(virt_addr);
L
Linus Torvalds 已提交
431 432
		break;
	case 32:
L
Len Brown 已提交
433
		*(u32 *) value = readl(virt_addr);
L
Linus Torvalds 已提交
434 435 436 437 438 439 440 441 442 443 444 445 446 447
		break;
	default:
		BUG();
	}

	if (efi_enabled) {
		if (iomem)
			iounmap(virt_addr);
	}

	return AE_OK;
}

acpi_status
L
Len Brown 已提交
448
acpi_os_write_memory(acpi_physical_address phys_addr, u32 value, u32 width)
L
Linus Torvalds 已提交
449
{
L
Len Brown 已提交
450 451
	void __iomem *virt_addr;
	int iomem = 0;
L
Linus Torvalds 已提交
452 453 454 455

	if (efi_enabled) {
		if (EFI_MEMORY_WB & efi_mem_attributes(phys_addr)) {
			/* HACK ALERT! We can use writeb/w/l on real memory too */
L
Len Brown 已提交
456
			virt_addr = (void __iomem *)phys_to_virt(phys_addr);
L
Linus Torvalds 已提交
457 458 459 460 461
		} else {
			iomem = 1;
			virt_addr = ioremap(phys_addr, width);
		}
	} else
L
Len Brown 已提交
462
		virt_addr = (void __iomem *)phys_to_virt(phys_addr);
L
Linus Torvalds 已提交
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484

	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();
	}

	if (iomem)
		iounmap(virt_addr);

	return AE_OK;
}

acpi_status
L
Len Brown 已提交
485 486
acpi_os_read_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
			       void *value, u32 width)
L
Linus Torvalds 已提交
487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509
{
	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 已提交
510 511
				   PCI_DEVFN(pci_id->device, pci_id->function),
				   reg, size, value);
L
Linus Torvalds 已提交
512 513 514

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

L
Linus Torvalds 已提交
516 517 518
EXPORT_SYMBOL(acpi_os_read_pci_configuration);

acpi_status
L
Len Brown 已提交
519 520
acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, u32 reg,
				acpi_integer value, u32 width)
L
Linus Torvalds 已提交
521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
{
	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 已提交
541 542
				    PCI_DEVFN(pci_id->device, pci_id->function),
				    reg, size, value);
L
Linus Torvalds 已提交
543 544 545 546 547

	return (result ? AE_ERROR : AE_OK);
}

/* TODO: Change code to take advantage of driver model more */
L
Len Brown 已提交
548 549 550 551
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 已提交
552
{
L
Len Brown 已提交
553 554 555 556 557 558
	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 已提交
559 560 561

	acpi_get_parent(chandle, &handle);
	if (handle != rhandle) {
L
Len Brown 已提交
562 563
		acpi_os_derive_pci_id_2(rhandle, handle, &pci_id, is_bridge,
					bus_number);
L
Linus Torvalds 已提交
564 565

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

L
Len Brown 已提交
569 570 571
		status =
		    acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL,
					  &temp);
L
Linus Torvalds 已提交
572
		if (ACPI_SUCCESS(status)) {
L
Len Brown 已提交
573 574
			pci_id->device = ACPI_HIWORD(ACPI_LODWORD(temp));
			pci_id->function = ACPI_LOWORD(ACPI_LODWORD(temp));
L
Linus Torvalds 已提交
575 576 577 578 579

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

			/* any nicer way to get bus number of bridge ? */
L
Len Brown 已提交
580 581 582 583 584 585 586 587
			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 已提交
588 589 590 591 592 593
				if (!ACPI_SUCCESS(status)) {
					/* Certainly broken...  FIX ME */
					return;
				}
				*is_bridge = 1;
				pci_id->bus = tu8;
L
Len Brown 已提交
594 595 596
				status =
				    acpi_os_read_pci_configuration(pci_id, 0x19,
								   &tu8, 8);
L
Linus Torvalds 已提交
597 598 599 600 601 602 603 604 605
				if (ACPI_SUCCESS(status)) {
					*bus_number = tu8;
				}
			} else
				*is_bridge = 0;
		}
	}
}

L
Len Brown 已提交
606 607 608
void acpi_os_derive_pci_id(acpi_handle rhandle,	/* upper bound  */
			   acpi_handle chandle,	/* current node */
			   struct acpi_pci_id **id)
L
Linus Torvalds 已提交
609 610 611 612 613 614 615
{
	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 已提交
616
static void acpi_os_execute_deferred(void *context)
L
Linus Torvalds 已提交
617
{
L
Len Brown 已提交
618
	struct acpi_os_dpc *dpc = NULL;
L
Linus Torvalds 已提交
619

L
Len Brown 已提交
620
	ACPI_FUNCTION_TRACE("os_execute_deferred");
L
Linus Torvalds 已提交
621

L
Len Brown 已提交
622
	dpc = (struct acpi_os_dpc *)context;
L
Linus Torvalds 已提交
623
	if (!dpc) {
L
Len Brown 已提交
624
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid (NULL) context.\n"));
L
Linus Torvalds 已提交
625 626 627 628 629 630 631 632 633 634 635
		return_VOID;
	}

	dpc->function(dpc->context);

	kfree(dpc);

	return_VOID;
}

acpi_status
L
Len Brown 已提交
636 637
acpi_os_queue_for_execution(u32 priority,
			    acpi_osd_exec_callback function, void *context)
L
Linus Torvalds 已提交
638
{
L
Len Brown 已提交
639 640 641
	acpi_status status = AE_OK;
	struct acpi_os_dpc *dpc;
	struct work_struct *task;
L
Linus Torvalds 已提交
642

L
Len Brown 已提交
643
	ACPI_FUNCTION_TRACE("os_queue_for_execution");
L
Linus Torvalds 已提交
644

L
Len Brown 已提交
645 646 647
	ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
			  "Scheduling function [%p(%p)] for deferred execution.\n",
			  function, context));
L
Linus Torvalds 已提交
648 649

	if (!function)
L
Len Brown 已提交
650
		return_ACPI_STATUS(AE_BAD_PARAMETER);
L
Linus Torvalds 已提交
651 652 653 654 655 656 657 658 659 660 661 662

	/*
	 * 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 已提交
663 664 665
	dpc =
	    kmalloc(sizeof(struct acpi_os_dpc) + sizeof(struct work_struct),
		    GFP_ATOMIC);
L
Linus Torvalds 已提交
666
	if (!dpc)
L
Len Brown 已提交
667
		return_ACPI_STATUS(AE_NO_MEMORY);
L
Linus Torvalds 已提交
668 669 670 671

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

L
Len Brown 已提交
672 673
	task = (void *)(dpc + 1);
	INIT_WORK(task, acpi_os_execute_deferred, (void *)dpc);
L
Linus Torvalds 已提交
674 675

	if (!queue_work(kacpid_wq, task)) {
L
Len Brown 已提交
676 677
		ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
				  "Call to queue_work() failed.\n"));
L
Linus Torvalds 已提交
678 679 680 681
		kfree(dpc);
		status = AE_ERROR;
	}

L
Len Brown 已提交
682
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
683
}
L
Len Brown 已提交
684

L
Linus Torvalds 已提交
685 686
EXPORT_SYMBOL(acpi_os_queue_for_execution);

L
Len Brown 已提交
687
void acpi_os_wait_events_complete(void *context)
L
Linus Torvalds 已提交
688 689 690
{
	flush_workqueue(kacpid_wq);
}
L
Len Brown 已提交
691

L
Linus Torvalds 已提交
692 693 694 695 696
EXPORT_SYMBOL(acpi_os_wait_events_complete);

/*
 * Allocate the memory for a spinlock and initialize it.
 */
L
Len Brown 已提交
697
acpi_status acpi_os_create_lock(acpi_handle * out_handle)
L
Linus Torvalds 已提交
698 699 700
{
	spinlock_t *lock_ptr;

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

	lock_ptr = acpi_os_allocate(sizeof(spinlock_t));

	spin_lock_init(lock_ptr);

L
Len Brown 已提交
707
	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Creating spinlock[%p].\n", lock_ptr));
L
Linus Torvalds 已提交
708 709 710

	*out_handle = lock_ptr;

L
Len Brown 已提交
711
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
712 713 714 715 716
}

/*
 * Deallocate the memory for a spinlock.
 */
L
Len Brown 已提交
717
void acpi_os_delete_lock(acpi_handle handle)
L
Linus Torvalds 已提交
718
{
L
Len Brown 已提交
719
	ACPI_FUNCTION_TRACE("os_create_lock");
L
Linus Torvalds 已提交
720

L
Len Brown 已提交
721
	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Deleting spinlock[%p].\n", handle));
L
Linus Torvalds 已提交
722 723 724 725 726 727 728

	acpi_os_free(handle);

	return_VOID;
}

acpi_status
L
Len Brown 已提交
729
acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle)
L
Linus Torvalds 已提交
730
{
L
Len Brown 已提交
731
	struct semaphore *sem = NULL;
L
Linus Torvalds 已提交
732

L
Len Brown 已提交
733
	ACPI_FUNCTION_TRACE("os_create_semaphore");
L
Linus Torvalds 已提交
734 735 736

	sem = acpi_os_allocate(sizeof(struct semaphore));
	if (!sem)
L
Len Brown 已提交
737
		return_ACPI_STATUS(AE_NO_MEMORY);
L
Linus Torvalds 已提交
738 739 740 741
	memset(sem, 0, sizeof(struct semaphore));

	sema_init(sem, initial_units);

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

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

L
Len Brown 已提交
747
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
748 749
}

L
Len Brown 已提交
750
EXPORT_SYMBOL(acpi_os_create_semaphore);
L
Linus Torvalds 已提交
751 752 753 754 755 756 757 758

/*
 * 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 已提交
759
acpi_status acpi_os_delete_semaphore(acpi_handle handle)
L
Linus Torvalds 已提交
760
{
L
Len Brown 已提交
761
	struct semaphore *sem = (struct semaphore *)handle;
L
Linus Torvalds 已提交
762

L
Len Brown 已提交
763
	ACPI_FUNCTION_TRACE("os_delete_semaphore");
L
Linus Torvalds 已提交
764 765

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

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

L
Len Brown 已提交
770 771
	acpi_os_free(sem);
	sem = NULL;
L
Linus Torvalds 已提交
772

L
Len Brown 已提交
773
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
774 775
}

L
Len Brown 已提交
776
EXPORT_SYMBOL(acpi_os_delete_semaphore);
L
Linus Torvalds 已提交
777 778 779 780 781 782 783 784 785 786

/*
 * 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 已提交
787
acpi_status acpi_os_wait_semaphore(acpi_handle handle, u32 units, u16 timeout)
L
Linus Torvalds 已提交
788
{
L
Len Brown 已提交
789 790 791
	acpi_status status = AE_OK;
	struct semaphore *sem = (struct semaphore *)handle;
	int ret = 0;
L
Linus Torvalds 已提交
792

L
Len Brown 已提交
793
	ACPI_FUNCTION_TRACE("os_wait_semaphore");
L
Linus Torvalds 已提交
794 795

	if (!sem || (units < 1))
L
Len Brown 已提交
796
		return_ACPI_STATUS(AE_BAD_PARAMETER);
L
Linus Torvalds 已提交
797 798

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

L
Len Brown 已提交
801 802
	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Waiting for semaphore[%p|%d|%d]\n",
			  handle, units, timeout));
L
Linus Torvalds 已提交
803 804 805 806

	if (in_atomic())
		timeout = 0;

L
Len Brown 已提交
807
	switch (timeout) {
L
Linus Torvalds 已提交
808 809 810 811 812 813 814
		/*
		 * 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 已提交
815 816
	case 0:
		if (down_trylock(sem))
L
Linus Torvalds 已提交
817 818 819 820 821 822 823
			status = AE_TIME;
		break;

		/*
		 * Wait Indefinitely:
		 * ------------------
		 */
L
Len Brown 已提交
824
	case ACPI_WAIT_FOREVER:
L
Linus Torvalds 已提交
825 826 827 828 829 830 831
		down(sem);
		break;

		/*
		 * Wait w/ Timeout:
		 * ----------------
		 */
L
Len Brown 已提交
832
	default:
L
Linus Torvalds 已提交
833 834 835
		// TODO: A better timeout algorithm?
		{
			int i = 0;
L
Len Brown 已提交
836
			static const int quantum_ms = 1000 / HZ;
L
Linus Torvalds 已提交
837 838 839

			ret = down_trylock(sem);
			for (i = timeout; (i > 0 && ret < 0); i -= quantum_ms) {
840
				schedule_timeout_interruptible(1);
L
Linus Torvalds 已提交
841 842
				ret = down_trylock(sem);
			}
L
Len Brown 已提交
843

L
Linus Torvalds 已提交
844 845 846 847 848 849 850
			if (ret != 0)
				status = AE_TIME;
		}
		break;
	}

	if (ACPI_FAILURE(status)) {
L
Len Brown 已提交
851 852 853 854 855 856 857 858
		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 已提交
859 860
	}

L
Len Brown 已提交
861
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
862 863
}

L
Len Brown 已提交
864
EXPORT_SYMBOL(acpi_os_wait_semaphore);
L
Linus Torvalds 已提交
865 866 867 868

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

L
Len Brown 已提交
873
	ACPI_FUNCTION_TRACE("os_signal_semaphore");
L
Linus Torvalds 已提交
874 875

	if (!sem || (units < 1))
L
Len Brown 已提交
876
		return_ACPI_STATUS(AE_BAD_PARAMETER);
L
Linus Torvalds 已提交
877 878

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

L
Len Brown 已提交
881 882
	ACPI_DEBUG_PRINT((ACPI_DB_MUTEX, "Signaling semaphore[%p|%d]\n", handle,
			  units));
L
Linus Torvalds 已提交
883 884 885

	up(sem);

L
Len Brown 已提交
886
	return_ACPI_STATUS(AE_OK);
L
Linus Torvalds 已提交
887
}
L
Len Brown 已提交
888

L
Linus Torvalds 已提交
889 890 891
EXPORT_SYMBOL(acpi_os_signal_semaphore);

#ifdef ACPI_FUTURE_USAGE
L
Len Brown 已提交
892
u32 acpi_os_get_line(char *buffer)
L
Linus Torvalds 已提交
893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908
{

#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 已提交
909
#endif				/*  ACPI_FUTURE_USAGE  */
L
Linus Torvalds 已提交
910 911

/* Assumes no unreadable holes inbetween */
L
Len Brown 已提交
912
u8 acpi_os_readable(void *ptr, acpi_size len)
L
Linus Torvalds 已提交
913
{
L
Len Brown 已提交
914
#if defined(__i386__) || defined(__x86_64__)
L
Linus Torvalds 已提交
915
	char tmp;
L
Len Brown 已提交
916 917
	return !__get_user(tmp, (char __user *)ptr)
	    && !__get_user(tmp, (char __user *)ptr + len - 1);
L
Linus Torvalds 已提交
918 919 920 921 922
#endif
	return 1;
}

#ifdef ACPI_FUTURE_USAGE
L
Len Brown 已提交
923
u8 acpi_os_writable(void *ptr, acpi_size len)
L
Linus Torvalds 已提交
924 925 926 927 928 929 930
{
	/* 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 已提交
931
u32 acpi_os_get_thread_id(void)
L
Linus Torvalds 已提交
932 933 934 935 936 937 938
{
	if (!in_atomic())
		return current->pid;

	return 0;
}

L
Len Brown 已提交
939
acpi_status acpi_os_signal(u32 function, void *info)
L
Linus Torvalds 已提交
940
{
L
Len Brown 已提交
941
	switch (function) {
L
Linus Torvalds 已提交
942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960
	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 已提交
961

L
Linus Torvalds 已提交
962 963
EXPORT_SYMBOL(acpi_os_signal);

L
Len Brown 已提交
964
static int __init acpi_os_name_setup(char *str)
L
Linus Torvalds 已提交
965 966
{
	char *p = acpi_os_name;
L
Len Brown 已提交
967
	int count = ACPI_MAX_OVERRIDE_LEN - 1;
L
Linus Torvalds 已提交
968 969 970 971 972 973 974 975 976 977 978 979 980 981 982

	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 已提交
983

L
Linus Torvalds 已提交
984 985 986 987 988 989 990 991 992
}

__setup("acpi_os_name=", acpi_os_name_setup);

/*
 * _OSI control
 * empty string disables _OSI
 * TBD additional string adds to _OSI
 */
L
Len Brown 已提交
993
static int __init acpi_osi_setup(char *str)
L
Linus Torvalds 已提交
994 995 996 997
{
	if (str == NULL || *str == '\0') {
		printk(KERN_INFO PREFIX "_OSI method disabled\n");
		acpi_gbl_create_osi_method = FALSE;
L
Len Brown 已提交
998
	} else {
L
Linus Torvalds 已提交
999
		/* TBD */
L
Len Brown 已提交
1000 1001
		printk(KERN_ERR PREFIX "_OSI additional string ignored -- %s\n",
		       str);
L
Linus Torvalds 已提交
1002 1003 1004 1005 1006 1007 1008 1009
	}

	return 1;
}

__setup("acpi_osi=", acpi_osi_setup);

/* enable serialization to combat AE_ALREADY_EXISTS errors */
L
Len Brown 已提交
1010
static int __init acpi_serialize_setup(char *str)
L
Linus Torvalds 已提交
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029
{
	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 已提交
1030
static int __init acpi_wake_gpes_always_on_setup(char *str)
L
Linus Torvalds 已提交
1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
{
	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);

1041
static int __init acpi_hotkey_setup(char *str)
L
Luming Yu 已提交
1042
{
1043
	acpi_specific_hotkey_enabled = FALSE;
L
Luming Yu 已提交
1044 1045 1046
	return 1;
}

1047
__setup("acpi_generic_hotkey", acpi_hotkey_setup);
L
Luming Yu 已提交
1048

L
Linus Torvalds 已提交
1049 1050 1051 1052 1053 1054 1055
/*
 * 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);
1056 1057 1058 1059 1060 1061 1062

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

B
Bob Moore 已提交
1063
acpi_native_uint acpi_os_acquire_lock(acpi_handle handle)
1064 1065
{
	unsigned long flags;
L
Len Brown 已提交
1066
	spin_lock_irqsave((spinlock_t *) handle, flags);
1067 1068 1069 1070 1071 1072 1073
	return flags;
}

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

B
Bob Moore 已提交
1074
void acpi_os_release_lock(acpi_handle handle, acpi_native_uint flags)
1075
{
L
Len Brown 已提交
1076
	spin_unlock_irqrestore((spinlock_t *) handle, flags);
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096
}

#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 已提交
1097
acpi_os_create_cache(char *name, u16 size, u16 depth, acpi_cache_t ** cache)
1098
{
L
Len Brown 已提交
1099
	*cache = kmem_cache_create(name, size, 0, 0, NULL, NULL);
1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114
	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 已提交
1115
acpi_status acpi_os_purge_cache(acpi_cache_t * cache)
1116
{
L
Len Brown 已提交
1117 1118
	(void)kmem_cache_shrink(cache);
	return (AE_OK);
1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133
}

/*******************************************************************************
 *
 * 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 已提交
1134
acpi_status acpi_os_delete_cache(acpi_cache_t * cache)
1135
{
L
Len Brown 已提交
1136 1137
	(void)kmem_cache_destroy(cache);
	return (AE_OK);
1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153
}

/*******************************************************************************
 *
 * 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 已提交
1154
acpi_status acpi_os_release_object(acpi_cache_t * cache, void *object)
1155
{
L
Len Brown 已提交
1156 1157
	kmem_cache_free(cache, object);
	return (AE_OK);
1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173
}

/*******************************************************************************
 *
 * 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 已提交
1174
void *acpi_os_acquire_object(acpi_cache_t * cache)
1175
{
L
Len Brown 已提交
1176 1177 1178
	void *object = kmem_cache_alloc(cache, GFP_KERNEL);
	WARN_ON(!object);
	return object;
1179 1180 1181
}

#endif