Commit bb721a7a authored by Andy Grover's avatar Andy Grover Committed by Andy Grover

ACPI driver updates

Better IRQ routing
ACPI 2.0-enumerated processor perf state support
ACPI poweroff via magic sysrq
parent 7a47fa52
......@@ -9,7 +9,7 @@ export ACPI_CFLAGS
ACPI_CFLAGS := -D_LINUX -I$(CURDIR)/include
ifdef CONFIG_ACPI_DEBUG
ACPI_CFLAGS += -DACPI_DEBUG -Wno-unused
ACPI_CFLAGS += -DACPI_DEBUG
endif
EXTRA_CFLAGS += $(ACPI_CFLAGS)
......
/*
* acpi_ac.c - ACPI AC Adapter Driver ($Revision: 22 $)
* acpi_ac.c - ACPI AC Adapter Driver ($Revision: 23 $)
*
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
......@@ -296,6 +296,7 @@ acpi_ac_remove (
struct acpi_ac *ac = NULL;
ACPI_FUNCTION_TRACE("acpi_ac_remove");
if (!device || !acpi_driver_data(device))
return_VALUE(-EINVAL);
......
/*
* acpi_battery.c - ACPI Battery Driver ($Revision: 31 $)
* acpi_battery.c - ACPI Battery Driver ($Revision: 32 $)
*
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
......@@ -112,8 +112,9 @@ acpi_battery_get_info (
struct acpi_battery *battery,
struct acpi_battery_info **bif)
{
int result = 0;
acpi_status status = 0;
acpi_buffer buffer = {0, NULL};
acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
acpi_buffer format = {sizeof(ACPI_BATTERY_FORMAT_BIF),
ACPI_BATTERY_FORMAT_BIF};
acpi_buffer data = {0, NULL};
......@@ -126,9 +127,11 @@ acpi_battery_get_info (
/* Evalute _BIF */
status = acpi_evaluate(battery->handle, "_BIF", NULL, &buffer);
if (ACPI_FAILURE(status))
status = acpi_evaluate_object(battery->handle, "_BIF", NULL, &buffer);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _BIF\n"));
return_VALUE(-ENODEV);
}
package = (acpi_object *) buffer.pointer;
......@@ -136,29 +139,33 @@ acpi_battery_get_info (
status = acpi_extract_package(package, &format, &data);
if (status != AE_BUFFER_OVERFLOW) {
kfree(buffer.pointer);
return_VALUE(-ENODEV);
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BIF\n"));
result = -ENODEV;
goto end;
}
data.pointer = kmalloc(data.length, GFP_KERNEL);
if (!data.pointer) {
kfree(buffer.pointer);
return_VALUE(-ENOMEM);
result = -ENOMEM;
goto end;
}
memset(data.pointer, 0, data.length);
status = acpi_extract_package(package, &format, &data);
if (ACPI_FAILURE(status)) {
kfree(buffer.pointer);
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BIF\n"));
kfree(data.pointer);
return_VALUE(-ENODEV);
result = -ENODEV;
goto end;
}
end:
kfree(buffer.pointer);
(*bif) = data.pointer;
if (0 == result)
(*bif) = (struct acpi_battery_info *) data.pointer;
return_VALUE(0);
return_VALUE(result);
}
static int
......@@ -166,8 +173,9 @@ acpi_battery_get_status (
struct acpi_battery *battery,
struct acpi_battery_status **bst)
{
int result = 0;
acpi_status status = 0;
acpi_buffer buffer = {0, NULL};
acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
acpi_buffer format = {sizeof(ACPI_BATTERY_FORMAT_BST),
ACPI_BATTERY_FORMAT_BST};
acpi_buffer data = {0, NULL};
......@@ -180,9 +188,11 @@ acpi_battery_get_status (
/* Evalute _BST */
status = acpi_evaluate(battery->handle, "_BST", NULL, &buffer);
if (ACPI_FAILURE(status))
status = acpi_evaluate_object(battery->handle, "_BST", NULL, &buffer);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _BST\n"));
return_VALUE(-ENODEV);
}
package = (acpi_object *) buffer.pointer;
......@@ -190,29 +200,33 @@ acpi_battery_get_status (
status = acpi_extract_package(package, &format, &data);
if (status != AE_BUFFER_OVERFLOW) {
kfree(buffer.pointer);
return_VALUE(-ENODEV);
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BST\n"));
result = -ENODEV;
goto end;
}
data.pointer = kmalloc(data.length, GFP_KERNEL);
if (!data.pointer) {
kfree(buffer.pointer);
return_VALUE(-ENOMEM);
result = -ENOMEM;
goto end;
}
memset(data.pointer, 0, data.length);
status = acpi_extract_package(package, &format, &data);
if (ACPI_FAILURE(status)) {
kfree(buffer.pointer);
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error extracting _BST\n"));
kfree(data.pointer);
return_VALUE(-ENODEV);
result = -ENODEV;
goto end;
}
end:
kfree(buffer.pointer);
(*bst) = data.pointer;
if (0 == result)
(*bst) = (struct acpi_battery_status *) data.pointer;
return_VALUE(0);
return_VALUE(result);
}
......@@ -328,7 +342,7 @@ acpi_battery_read_info (
{
int result = 0;
struct acpi_battery *battery = (struct acpi_battery *) data;
struct acpi_battery_info *bif = 0;
struct acpi_battery_info *bif = NULL;
char *units = "?";
char *p = page;
int len = 0;
......@@ -403,8 +417,7 @@ acpi_battery_read_info (
bif->oem_info);
end:
if (bif)
kfree(bif);
kfree(bif);
len = (p - page);
if (len <= off+count) *eof = 1;
......@@ -490,8 +503,7 @@ acpi_battery_read_state (
(u32) bst->present_voltage);
end:
if (bst)
kfree(bst);
kfree(bst);
len = (p - page);
if (len <= off+count) *eof = 1;
......
/*
* acpi_bus.c - ACPI Bus Driver ($Revision: 56 $)
* acpi_bus.c - ACPI Bus Driver ($Revision: 66 $)
*
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
*
......@@ -77,6 +77,8 @@ static struct acpi_blacklist_item acpi_blacklist[] __initdata =
{"SONY ", "U0 ", 0x20010313, ACPI_TABLE_DSDT, less_than_or_equal, "ACPI driver problem", 1},
/* Compaq Presario 800, Insyde BIOS */
{"INT440", "SYSFexxx", 0x00001001, ACPI_TABLE_DSDT, less_than_or_equal, "Does not use _REG to protect EC OpRegions", 1},
/* IBM 600E - _ADR should return 7, but it returns 1 */
{"IBM ", "TP600E ", 0x00000105, ACPI_TABLE_DSDT, less_than_or_equal, "Incorrect _ADR", 1},
{""}
};
......@@ -266,34 +268,6 @@ acpi_bus_data_handler (
}
static void
acpi_bus_data_handler_powerf (
acpi_handle handle,
u32 function,
void *context)
{
ACPI_FUNCTION_TRACE("acpi_bus_data_handler_powerf");
/* TBD */
return_VOID;
}
static void
acpi_bus_data_handler_sleepf (
acpi_handle handle,
u32 function,
void *context)
{
ACPI_FUNCTION_TRACE("acpi_bus_data_handler_sleepf");
/* TBD */
return_VOID;
}
int
acpi_bus_get_device (
acpi_handle handle,
......@@ -1044,8 +1018,10 @@ acpi_bus_match (
if (!device || !driver)
return -EINVAL;
if (0 != strstr(driver->ids, device->pnp.hardware_id))
return 0;
if (device->flags.hardware_id) {
if (0 != strstr(driver->ids, device->pnp.hardware_id))
return 0;
}
if (device->flags.compatible_ids) {
acpi_status status = AE_OK;
......@@ -1055,8 +1031,8 @@ acpi_bus_match (
memset(cid, 0, sizeof(cid));
status = acpi_evaluate_object(device->handle, "_CID",
NULL, &buffer);
status = acpi_evaluate_object(device->handle, "_CID", NULL,
&buffer);
if (ACPI_FAILURE(status) || !buffer.pointer)
return -ENOENT;
......@@ -1072,10 +1048,11 @@ acpi_bus_match (
break;
case ACPI_TYPE_PACKAGE:
/* TBD: Support CID packages */
default:
return -ENOENT;
}
if (!cid[0])
return -ENOENT;
if (0 != strstr(cid, device->pnp.hardware_id))
return 0;
}
......@@ -1144,13 +1121,13 @@ acpi_bus_driver_init (
/**
* acpi_bus_bind
* acpi_bus_attach
* -------------
* Callback for acpi_bus_walk() used to find devices that match a specific
* driver's criteria and bind the driver to the device.
* driver's criteria and then attach the driver.
*/
static int
acpi_bus_bind (
acpi_bus_attach (
struct acpi_device *device,
int level,
void *data)
......@@ -1158,7 +1135,7 @@ acpi_bus_bind (
int result = 0;
struct acpi_driver *driver = NULL;
ACPI_FUNCTION_TRACE("acpi_bus_bind");
ACPI_FUNCTION_TRACE("acpi_bus_attach");
if (!device || !data)
return_VALUE(-EINVAL);
......@@ -1191,13 +1168,13 @@ acpi_bus_bind (
/**
* acpi_bus_unbind
* ---------------
* acpi_bus_unattach
* -----------------
* Callback for acpi_bus_walk() used to find devices that match a specific
* driver's criteria and unbind the driver from the device.
* driver's criteria and unattach the driver.
*/
static int
acpi_bus_unbind (
acpi_bus_unattach (
struct acpi_device *device,
int level,
void *data)
......@@ -1205,7 +1182,7 @@ acpi_bus_unbind (
int result = 0;
struct acpi_driver *driver = (struct acpi_driver *) data;
ACPI_FUNCTION_TRACE("acpi_bus_unbind");
ACPI_FUNCTION_TRACE("acpi_bus_unattach");
if (!device || !driver)
return_VALUE(-EINVAL);
......@@ -1291,7 +1268,7 @@ acpi_bus_register_driver (
list_add_tail(&driver->node, &acpi_bus_drivers);
up(&acpi_bus_drivers_lock);
acpi_bus_walk(acpi_root, acpi_bus_bind,
acpi_bus_walk(acpi_root, acpi_bus_attach,
WALK_DOWN, driver);
return_VALUE(driver->references);
......@@ -1313,7 +1290,7 @@ acpi_bus_unregister_driver (
if (!driver)
return_VALUE(-EINVAL);
acpi_bus_walk(acpi_root, acpi_bus_unbind, WALK_UP, driver);
acpi_bus_walk(acpi_root, acpi_bus_unattach, WALK_UP, driver);
if (driver->references)
return_VALUE(driver->references);
......@@ -1395,8 +1372,8 @@ acpi_bus_add (
char bus_id[5] = {'?',0};
acpi_buffer buffer = {sizeof(bus_id), bus_id};
acpi_device_info info;
char *hid = "?";
char *uid = "0";
char *hid = NULL;
char *uid = NULL;
int i = 0;
ACPI_FUNCTION_TRACE("acpi_bus_add");
......@@ -1414,6 +1391,37 @@ acpi_bus_add (
device->handle = handle;
device->parent = parent;
memset(&info, 0, sizeof(acpi_device_info));
/*
* Bus ID
* ------
* The device's Bus ID is simply the object name.
* TBD: Shouldn't this value be unique (within the ACPI namespace)?
*/
switch (type) {
case ACPI_BUS_TYPE_SYSTEM:
sprintf(device->pnp.bus_id, "%s", "ACPI");
break;
case ACPI_BUS_TYPE_POWER_BUTTON:
sprintf(device->pnp.bus_id, "%s", "PWRF");
break;
case ACPI_BUS_TYPE_SLEEP_BUTTON:
sprintf(device->pnp.bus_id, "%s", "SLPF");
break;
default:
acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
/* Clean up trailing underscores (if any) */
for (i = 3; i > 1; i--) {
if (bus_id[i] == '_')
bus_id[i] = '\0';
else
break;
}
sprintf(device->pnp.bus_id, "%s", bus_id);
break;
}
/*
* Flags
* -----
......@@ -1456,35 +1464,6 @@ acpi_bus_add (
* TBD: Synch with Core's enumeration/initialization process.
*/
/*
* Bus ID
* ------
* The device's Bus ID is simply the object name.
* TBD: Shouldn't this value be unique (within the ACPI namespace)?
*/
switch (type) {
case ACPI_BUS_TYPE_SYSTEM:
sprintf(device->pnp.bus_id, "%s", "ACPI");
break;
case ACPI_BUS_TYPE_POWER_BUTTON:
sprintf(device->pnp.bus_id, "%s", "PWRF");
break;
case ACPI_BUS_TYPE_SLEEP_BUTTON:
sprintf(device->pnp.bus_id, "%s", "SLPF");
break;
default:
acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer);
/* Clean up trailing underscores (if any) */
for (i = 3; i > 1; i--) {
if (bus_id[i] == '_')
bus_id[i] = '\0';
else
break;
}
sprintf(device->pnp.bus_id, "%s", bus_id);
break;
}
/*
* Hardware ID, Unique ID, & Bus Address
* -------------------------------------
......@@ -1505,8 +1484,10 @@ acpi_bus_add (
hid = info.hardware_id;
if (info.valid & ACPI_VALID_UID)
uid = info.unique_id;
if (info.valid & ACPI_VALID_ADR)
if (info.valid & ACPI_VALID_ADR) {
device->pnp.bus_address = info.address;
device->flags.bus_address = 1;
}
break;
case ACPI_BUS_TYPE_POWER:
hid = ACPI_POWER_HID;
......@@ -1528,8 +1509,25 @@ acpi_bus_add (
break;
}
sprintf(device->pnp.hardware_id, "%s", hid);
sprintf(device->pnp.unique_id, "%s", uid);
/*
* \_SB
* ----
* Fix for the system root bus device -- the only root-level device.
*/
if ((parent == ACPI_ROOT_OBJECT) && (type == ACPI_BUS_TYPE_DEVICE)) {
hid = ACPI_BUS_HID;
sprintf(device->pnp.device_name, "%s", ACPI_BUS_DEVICE_NAME);
sprintf(device->pnp.device_class, "%s", ACPI_BUS_CLASS);
}
if (hid) {
sprintf(device->pnp.hardware_id, "%s", hid);
device->flags.hardware_id = 1;
}
if (uid) {
sprintf(device->pnp.unique_id, "%s", uid);
device->flags.unique_id = 1;
}
/*
* Power Management
......@@ -1555,18 +1553,13 @@ acpi_bus_add (
* Context
* -------
* Attach this 'struct acpi_device' to the ACPI object. This makes
* resolutions from handle->device very efficient. Note that since we
* attach multiple context to the root object (system device plus all
* fixed-feature devices) we must use alternate handlers.
* resolutions from handle->device very efficient. Note that we need
* to be careful with fixed-feature devices as they all attach to the
* root object.
*/
switch (type) {
case ACPI_BUS_TYPE_POWER_BUTTON:
status = acpi_attach_data(device->handle,
acpi_bus_data_handler_powerf, device);
break;
case ACPI_BUS_TYPE_SLEEP_BUTTON:
status = acpi_attach_data(device->handle,
acpi_bus_data_handler_sleepf, device);
break;
default:
status = acpi_attach_data(device->handle,
......@@ -1591,21 +1584,9 @@ acpi_bus_add (
else
list_add_tail(&device->node, &device->parent->children);
/*
* \_SB
* ----
* Fix for the system root bus device -- the only root-level device.
*/
if ((type == ACPI_BUS_TYPE_DEVICE) && (parent == ACPI_ROOT_OBJECT)) {
sprintf(device->pnp.hardware_id, "%s", ACPI_BUS_HID);
sprintf(device->pnp.device_name, "%s", ACPI_BUS_DEVICE_NAME);
sprintf(device->pnp.device_class, "%s", ACPI_BUS_CLASS);
}
#ifdef CONFIG_ACPI_DEBUG
{
char *type_string = NULL;
char *message = NULL;
char name[80] = {'?','\0'};
acpi_buffer buffer = {sizeof(name), name};
......@@ -1640,7 +1621,7 @@ acpi_bus_add (
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %s %s [%p]\n",
type_string, name, handle));
}
#endif
#endif /*CONFIG_ACPI_DEBUG*/
/*
* Global Device Hierarchy:
......@@ -1650,14 +1631,30 @@ acpi_bus_add (
acpi_device_register(device, parent);
/*
* Find Driver
* -----------
* Check to see if there's a driver installed for this kind of device.
* Bind _ADR-Based Devices
* -----------------------
* If there's a a bus address (_ADR) then we utilize the parent's
* 'bind' function (if exists) to bind the ACPI- and natively-
* enumerated device representations.
*/
acpi_bus_find_driver(device);
if (device->flags.bus_address) {
if (device->parent && device->parent->ops.bind)
device->parent->ops.bind(device);
}
end:
/*
* Locate & Attach Driver
* ----------------------
* If there's a hardware id (_HID) or compatible ids (_CID) we check
* to see if there's a driver installed for this kind of device. Note
* that drivers can install before or after a device in enumerated.
*
* TBD: Assumes LDM provides driver hot-plug capability.
*/
if (device->flags.hardware_id || device->flags.compatible_ids)
acpi_bus_find_driver(device);
end:
if (0 != result) {
kfree(device);
return_VALUE(result);
......@@ -1774,13 +1771,11 @@ acpi_bus_scan (
* If the device is present, enabled, and functioning then
* parse its scope (depth-first). Note that we need to
* represent absent devices to facilitate PnP notifications
* -- but we only the subtree head (not all of its children,
* -- but only the subtree head (not all of its children,
* which will be enumerated when the parent is inserted).
*
* TBD: Need notifications and other detection mechanisms
* in place before we can fully implement this.
*
* if (STRUCT_TO_INT(child->status) & 0x0B) {
*/
if (child->status.present) {
status = acpi_get_next_object(ACPI_TYPE_ANY, chandle,
......@@ -1883,6 +1878,55 @@ acpi_blacklisted(void)
}
static int __init
acpi_bus_init_irq (void)
{
int result = 0;
acpi_status status = AE_OK;
acpi_object arg = {ACPI_TYPE_INTEGER};
acpi_object_list arg_list = {1, &arg};
int irq_model = 0;
char *message = NULL;
ACPI_FUNCTION_TRACE("acpi_bus_init_irq");
/*
* Let the system know what interrupt model we are using by
* evaluating the \_PIC object, if exists.
*/
result = acpi_get_interrupt_model(&irq_model);
if (0 != result)
return_VALUE(result);
switch (irq_model) {
case ACPI_INT_MODEL_PIC:
message = "PIC";
break;
case ACPI_INT_MODEL_IOAPIC:
message = "IOAPIC";
break;
case ACPI_INT_MODEL_IOSAPIC:
message = "IOSAPIC";
break;
default:
message = "UNKNOWN";
break;
}
printk(KERN_INFO PREFIX "Using %s for interrupt routing\n", message);
arg.integer.value = irq_model;
status = acpi_evaluate_object(NULL, "\\_PIC", &arg_list, NULL);
if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PIC\n"));
return_VALUE(-ENODEV);
}
return_VALUE(0);
}
static int __init
acpi_bus_init (void)
{
......@@ -1928,7 +1972,7 @@ acpi_bus_init (void)
progress++;
/*
* [2] Get a separate copy of the FADT for use by other drivers.
* [3] Get a separate copy of the FADT for use by other drivers.
*/
status = acpi_get_table(ACPI_TABLE_FADT, 1, &buffer);
if (ACPI_FAILURE(status)) {
......@@ -1940,7 +1984,7 @@ acpi_bus_init (void)
progress++;
/*
* [3] Enable the ACPI Core Subsystem.
* [4] Enable the ACPI Core Subsystem.
*/
status = acpi_enable_subsystem(ACPI_FULL_INITIALIZATION);
if (ACPI_FAILURE(status)) {
......@@ -1954,7 +1998,14 @@ acpi_bus_init (void)
progress++;
/*
* [4] Register for all standard device notifications.
* [5] Register for all standard device notifications.
*/
result = acpi_bus_init_irq();
if (0 != result)
goto end;
/*
* [6] Register for all standard device notifications.
*/
status = acpi_install_notify_handler(ACPI_ROOT_OBJECT, ACPI_SYSTEM_NOTIFY, &acpi_bus_notify, NULL);
if (ACPI_FAILURE(status)) {
......@@ -1966,7 +2017,7 @@ acpi_bus_init (void)
progress++;
/*
* [5] Create the root device.
* [7] Create the root device.
*/
result = acpi_bus_add(&acpi_root, NULL, ACPI_ROOT_OBJECT,
ACPI_BUS_TYPE_SYSTEM);
......@@ -1976,7 +2027,7 @@ acpi_bus_init (void)
progress++;
/*
* [6] Create the root file system.
* [8] Create the root file system.
*/
acpi_device_dir(acpi_root) = proc_mkdir(ACPI_BUS_FILE_ROOT, NULL);
if (!acpi_root) {
......@@ -1988,7 +2039,7 @@ acpi_bus_init (void)
progress++;
/*
* [7] Install drivers required for proper enumeration of the
* [9] Install drivers required for proper enumeration of the
* ACPI namespace.
*/
acpi_system_init(); /* ACPI System */
......@@ -2003,7 +2054,7 @@ acpi_bus_init (void)
progress++;
/*
* [8] Enumerate devices in the ACPI namespace.
* [10] Enumerate devices in the ACPI namespace.
*/
result = acpi_bus_scan_fixed(acpi_root);
......@@ -2017,11 +2068,12 @@ acpi_bus_init (void)
end:
if (0 != result) {
switch (progress) {
case 9:
case 8: remove_proc_entry("ACPI", NULL);
case 7: acpi_bus_remove(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
case 6: acpi_remove_notify_handler(ACPI_ROOT_OBJECT,
case 10:
case 9: remove_proc_entry("ACPI", NULL);
case 8: acpi_bus_remove(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
case 7: acpi_remove_notify_handler(ACPI_ROOT_OBJECT,
ACPI_SYSTEM_NOTIFY, &acpi_bus_notify);
case 6:
case 5:
case 4:
case 3:
......@@ -2085,6 +2137,9 @@ acpi_init (void)
printk(KERN_INFO PREFIX "Core Subsystem revision %08x\n",
ACPI_CA_VERSION);
/* Initial core debug level excludes drivers, so include them now */
acpi_set_debug(ACPI_DEBUG_LOW);
if (acpi_disabled) {
printk(KERN_INFO PREFIX "Disabled via command line (acpi=off)\n");
return -ENODEV;
......@@ -2143,3 +2198,4 @@ subsys_initcall(acpi_init);
#endif
__setup("acpi=", acpi_setup);
/*
* acpi_bus.h - ACPI Bus Driver ($Revision: 17 $)
* acpi_bus.h - ACPI Bus Driver ($Revision: 19 $)
*
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
......@@ -96,8 +96,9 @@ typedef int (*acpi_op_stop) (struct acpi_device *device, int type);
typedef int (*acpi_op_suspend) (struct acpi_device *device, int state);
typedef int (*acpi_op_resume) (struct acpi_device *device, int state);
typedef int (*acpi_op_scan) (struct acpi_device *device);
typedef int (*acpi_op_bind) (struct acpi_device *device);
struct acpi_driver_ops {
struct acpi_device_ops {
acpi_op_add add;
acpi_op_remove remove;
acpi_op_lock lock;
......@@ -106,6 +107,7 @@ struct acpi_driver_ops {
acpi_op_suspend suspend;
acpi_op_resume resume;
acpi_op_scan scan;
acpi_op_bind bind;
};
struct acpi_driver {
......@@ -114,7 +116,7 @@ struct acpi_driver {
char class[80];
int references;
char *ids; /* Supported Hardware IDs */
struct acpi_driver_ops ops;
struct acpi_device_ops ops;
};
enum acpi_blacklist_predicates
......@@ -157,14 +159,18 @@ struct acpi_device_status {
/* Flags */
struct acpi_device_flags {
u8 dynamic_status:1;
u8 compatible_ids:1;
u8 removable:1;
u8 ejectable:1;
u8 lockable:1;
u8 suprise_removal_ok:1;
u8 power_manageable:1;
u8 performance_manageable:1;
u32 dynamic_status:1;
u32 hardware_id:1;
u32 compatible_ids:1;
u32 bus_address:1;
u32 unique_id:1;
u32 removable:1;
u32 ejectable:1;
u32 lockable:1;
u32 suprise_removal_ok:1;
u32 power_manageable:1;
u32 performance_manageable:1;
u32 reserved:21;
};
......@@ -206,13 +212,13 @@ struct acpi_device_pnp {
/* Power Management */
struct acpi_device_power_flags {
u8 explicit_get:1; /* _PSC present? */
u8 power_resources:1; /* Power resources */
u8 inrush_current:1; /* Serialize Dx->D0 */
u8 wake_capable:1; /* Wakeup supported? */
u8 wake_enabled:1; /* Enabled for wakeup */
u8 power_removed:1; /* Optimize Dx->D0 */
u8 reserved:2;
u32 explicit_get:1; /* _PSC present? */
u32 power_resources:1; /* Power resources */
u32 inrush_current:1; /* Serialize Dx->D0 */
u32 wake_capable:1; /* Wakeup supported? */
u32 wake_enabled:1; /* Enabled for wakeup */
u32 power_removed:1; /* Optimize Dx->D0 */
u32 reserved:26;
};
struct acpi_device_power_state {
......@@ -270,6 +276,7 @@ struct acpi_device {
struct acpi_device_power power;
struct acpi_device_perf performance;
struct acpi_device_dir dir;
struct acpi_device_ops ops;
struct acpi_driver *driver;
void *driver_data;
#ifdef CONFIG_LDM
......
/*
* acpi_button.c - ACPI Button Driver ($Revision: 22 $)
* acpi_button.c - ACPI Button Driver ($Revision: 24 $)
*
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
......@@ -69,7 +69,7 @@ struct acpi_button {
#include <linux/compatmac.h>
#include <linux/proc_fs.h>
struct proc_dir_entry *acpi_button_dir = NULL;
static struct proc_dir_entry *acpi_button_dir = NULL;
static int
......@@ -81,7 +81,6 @@ acpi_button_read_info (
int *eof,
void *data)
{
int result = 0;
struct acpi_button *button = (struct acpi_button *) data;
char *p = page;
int len = 0;
......@@ -111,22 +110,42 @@ acpi_button_add_fs (
struct acpi_device *device)
{
struct proc_dir_entry *entry = NULL;
struct acpi_button *button = NULL;
ACPI_FUNCTION_TRACE("acpi_button_add_fs");
if (!device || !acpi_driver_data(device))
return_VALUE(-EINVAL);
button = acpi_driver_data(device);
if (!acpi_button_dir) {
acpi_button_dir = proc_mkdir(ACPI_BUTTON_CLASS, acpi_root_dir);
if (!acpi_button_dir)
return_VALUE(-ENODEV);
}
if (!acpi_device_dir(device)) {
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device),
switch (button->type) {
case ACPI_BUTTON_TYPE_POWER:
case ACPI_BUTTON_TYPE_POWERF:
entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_POWER,
acpi_button_dir);
if (!acpi_device_dir(device))
return_VALUE(-ENODEV);
break;
case ACPI_BUTTON_TYPE_SLEEP:
case ACPI_BUTTON_TYPE_SLEEPF:
entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_SLEEP,
acpi_button_dir);
break;
case ACPI_BUTTON_TYPE_LID:
entry = proc_mkdir(ACPI_BUTTON_SUBCLASS_LID,
acpi_button_dir);
break;
}
acpi_device_dir(device) = proc_mkdir(acpi_device_bid(device), entry);
if (!acpi_device_dir(device))
return_VALUE(-ENODEV);
/* 'info' [R] */
entry = create_proc_entry(ACPI_BUTTON_FILE_INFO,
S_IRUGO, acpi_device_dir(device));
......@@ -227,37 +246,46 @@ acpi_button_add (
button->device = device;
button->handle = device->handle;
sprintf(acpi_device_class(device), "%s", ACPI_BUTTON_CLASS);
acpi_driver_data(device) = button;
/*
* Determine the button type (via hid), as fixed-feature buttons
* need to be handled a bit differently than generic-space.
*/
if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWERF)) {
button->type = ACPI_BUTTON_TYPE_POWERF;
sprintf(acpi_device_name(device), "%s",
ACPI_BUTTON_DEVICE_NAME_POWERF);
}
else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEPF)) {
button->type = ACPI_BUTTON_TYPE_SLEEPF;
sprintf(acpi_device_name(device), "%s",
ACPI_BUTTON_DEVICE_NAME_SLEEPF);
}
else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWER)) {
if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWER)) {
button->type = ACPI_BUTTON_TYPE_POWER;
sprintf(acpi_device_name(device), "%s",
ACPI_BUTTON_DEVICE_NAME_POWER);
sprintf(acpi_device_class(device), "%s/%s",
ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
}
else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_POWERF)) {
button->type = ACPI_BUTTON_TYPE_POWERF;
sprintf(acpi_device_name(device), "%s",
ACPI_BUTTON_DEVICE_NAME_POWERF);
sprintf(acpi_device_class(device), "%s/%s",
ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_POWER);
}
else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEP)) {
button->type = ACPI_BUTTON_TYPE_SLEEP;
sprintf(acpi_device_name(device), "%s",
ACPI_BUTTON_DEVICE_NAME_SLEEP);
sprintf(acpi_device_class(device), "%s/%s",
ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
}
else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_SLEEPF)) {
button->type = ACPI_BUTTON_TYPE_SLEEPF;
sprintf(acpi_device_name(device), "%s",
ACPI_BUTTON_DEVICE_NAME_SLEEPF);
sprintf(acpi_device_class(device), "%s/%s",
ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_SLEEP);
}
else if (!strcmp(acpi_device_hid(device), ACPI_BUTTON_HID_LID)) {
button->type = ACPI_BUTTON_TYPE_LID;
sprintf(acpi_device_name(device), "%s",
ACPI_BUTTON_DEVICE_NAME_LID);
sprintf(acpi_device_class(device), "%s/%s",
ACPI_BUTTON_CLASS, ACPI_BUTTON_SUBCLASS_LID);
}
else {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unsupported hid [%s]\n",
......
/*
* acpi_drivers.h ($Revision: 17 $)
* acpi_drivers.h ($Revision: 23 $)
*
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
......@@ -30,7 +30,7 @@
#include "acpi_bus.h"
#define ACPI_DRIVER_VERSION 0x20020308
#define ACPI_DRIVER_VERSION 0x20020404
#define ACPI_MAX_STRING 80
......@@ -84,26 +84,32 @@
-------------------------------------------------------------------------- */
#define ACPI_BUTTON_COMPONENT 0x00080000
#define ACPI_BUTTON_CLASS "button"
#define ACPI_BUTTON_HID_LID "PNP0C0D"
#define ACPI_BUTTON_HID_POWER "PNP0C0C"
#define ACPI_BUTTON_HID_POWERF "ACPI_FPB"
#define ACPI_BUTTON_HID_SLEEP "PNP0C0E"
#define ACPI_BUTTON_HID_SLEEPF "ACPI_FSB"
#define ACPI_BUTTON_DRIVER_NAME "ACPI Button Driver"
#define ACPI_BUTTON_DEVICE_NAME_POWER "Power Button"
#define ACPI_BUTTON_DEVICE_NAME_POWERF "Power Button"
#define ACPI_BUTTON_DEVICE_NAME_SLEEP "Sleep Button"
#define ACPI_BUTTON_DEVICE_NAME_SLEEPF "Sleep Button"
#define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch"
#define ACPI_BUTTON_CLASS "button"
#define ACPI_BUTTON_FILE_INFO "info"
#define ACPI_BUTTON_TYPE_UNKNOWN 0x00
#define ACPI_BUTTON_NOTIFY_STATUS 0x80
#define ACPI_BUTTON_SUBCLASS_POWER "power"
#define ACPI_BUTTON_HID_POWER "PNP0C0C"
#define ACPI_BUTTON_HID_POWERF "ACPI_FPB"
#define ACPI_BUTTON_DEVICE_NAME_POWER "Power Button (CM)"
#define ACPI_BUTTON_DEVICE_NAME_POWERF "Power Button (FF)"
#define ACPI_BUTTON_TYPE_POWER 0x01
#define ACPI_BUTTON_TYPE_POWERF 0x02
#define ACPI_BUTTON_SUBCLASS_SLEEP "sleep"
#define ACPI_BUTTON_HID_SLEEP "PNP0C0E"
#define ACPI_BUTTON_HID_SLEEPF "ACPI_FSB"
#define ACPI_BUTTON_DEVICE_NAME_SLEEP "Sleep Button (CM)"
#define ACPI_BUTTON_DEVICE_NAME_SLEEPF "Sleep Button (FF)"
#define ACPI_BUTTON_TYPE_SLEEP 0x03
#define ACPI_BUTTON_TYPE_SLEEPF 0x04
#define ACPI_BUTTON_SUBCLASS_LID "lid"
#define ACPI_BUTTON_HID_LID "PNP0C0D"
#define ACPI_BUTTON_DEVICE_NAME_LID "Lid Switch"
#define ACPI_BUTTON_TYPE_LID 0x05
#define ACPI_BUTTON_NOTIFY_STATUS 0x80
/* --------------------------------------------------------------------------
......@@ -217,7 +223,7 @@ void acpi_power_exit (void);
#define ACPI_PROCESSOR_LIMIT_INCREMENT 0x01
#define ACPI_PROCESSOR_LIMIT_DECREMENT 0x02
int acpi_processor_set_limit(acpi_handle handle, int flags, int *state);
int acpi_processor_set_thermal_limit(acpi_handle handle, int type);
/* --------------------------------------------------------------------------
......
/*
* acpi_ec.c - ACPI Embedded Controller Driver ($Revision: 27 $)
* acpi_ec.c - ACPI Embedded Controller Driver ($Revision: 28 $)
*
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
......@@ -345,7 +345,7 @@ acpi_ec_gpe_handler (
if (0 != acpi_ec_query(ec, &value))
return;
query_data = kmalloc(sizeof(struct acpi_ec_query_data), GFP_KERNEL);
query_data = kmalloc(sizeof(struct acpi_ec_query_data), GFP_ATOMIC);
if (!query_data)
return;
query_data->handle = ec->handle;
......
/*
* acpi_osl.c - OS-dependent functions ($Revision: 65 $)
* acpi_osl.c - OS-dependent functions ($Revision: 69 $)
*
* Copyright (C) 2000 Andrew Henroid
* Copyright (C) 2001 Andrew Grover
......@@ -125,13 +125,13 @@ acpi_os_vprintf(const NATIVE_CHAR *fmt, va_list args)
}
void *
acpi_os_allocate(u32 size)
acpi_os_allocate(ACPI_SIZE size)
{
return kmalloc(size, GFP_KERNEL);
}
void *
acpi_os_callocate(u32 size)
acpi_os_callocate(ACPI_SIZE size)
{
void *ptr = acpi_os_allocate(size);
if (ptr)
......@@ -148,21 +148,22 @@ acpi_os_free(void *ptr)
acpi_status
acpi_os_get_root_pointer(u32 flags, ACPI_PHYSICAL_ADDRESS *phys_addr)
acpi_os_get_root_pointer(u32 flags, ACPI_POINTER *addr)
{
#ifndef CONFIG_ACPI_EFI
if (ACPI_FAILURE(acpi_find_root_pointer(flags, phys_addr))) {
if (ACPI_FAILURE(acpi_find_root_pointer(flags, addr))) {
printk(KERN_ERR PREFIX "System description tables not found\n");
return AE_NOT_FOUND;
}
#else /*CONFIG_ACPI_EFI*/
addr->pointer_type = ACPI_PHYSICAL_POINTER;
if (efi.acpi20)
*phys_addr = (ACPI_PHYSICAL_ADDRESS) efi.acpi20;
addr->pointer.physical = (ACPI_PHYSICAL_ADDRESS) efi.acpi20;
else if (efi.acpi)
*phys_addr = (ACPI_PHYSICAL_ADDRESS) efi.acpi;
addr->pointer.physical = (ACPI_PHYSICAL_ADDRESS) efi.acpi;
else {
printk(KERN_ERR PREFIX "System description tables not found\n");
*phys_addr = 0;
addr->pointer.physical = 0;
return AE_NOT_FOUND;
}
#endif /*CONFIG_ACPI_EFI*/
......@@ -171,7 +172,7 @@ acpi_os_get_root_pointer(u32 flags, ACPI_PHYSICAL_ADDRESS *phys_addr)
}
acpi_status
acpi_os_map_memory(ACPI_PHYSICAL_ADDRESS phys, u32 size, void **virt)
acpi_os_map_memory(ACPI_PHYSICAL_ADDRESS phys, ACPI_SIZE size, void **virt)
{
if (phys > ULONG_MAX) {
printk(KERN_ERR PREFIX "Cannot map memory that high\n");
......@@ -189,7 +190,7 @@ acpi_os_map_memory(ACPI_PHYSICAL_ADDRESS phys, u32 size, void **virt)
}
void
acpi_os_unmap_memory(void *virt, u32 size)
acpi_os_unmap_memory(void *virt, ACPI_SIZE size)
{
iounmap(virt);
}
......@@ -441,14 +442,14 @@ acpi_os_load_module (
ACPI_FUNCTION_TRACE ("os_load_module");
if (!module_name)
return AE_BAD_PARAMETER;
return_ACPI_STATUS (AE_BAD_PARAMETER);
if (0 > request_module(module_name)) {
ACPI_DEBUG_PRINT ((ACPI_DB_WARN, "Unable to load module [%s].\n", module_name));
return AE_ERROR;
return_ACPI_STATUS (AE_ERROR);
}
return AE_OK;
return_ACPI_STATUS (AE_OK);
}
acpi_status
......@@ -481,7 +482,7 @@ acpi_os_queue_exec (
strcpy(current->comm, "kacpidpc");
if (!dpc || !dpc->function)
return AE_BAD_PARAMETER;
return_ACPI_STATUS (AE_BAD_PARAMETER);
ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Executing function [%p(%p)].\n", dpc->function, dpc->context));
......@@ -489,7 +490,7 @@ acpi_os_queue_exec (
kfree(dpc);
return 1;
return_ACPI_STATUS (AE_OK);
}
static void
......@@ -504,7 +505,7 @@ acpi_os_schedule_exec (
dpc = (ACPI_OS_DPC*)context;
if (!dpc) {
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Invalid (NULL) context.\n"));
return;
return_VOID;
}
ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Creating new thread to run function [%p(%p)].\n", dpc->function, dpc->context));
......@@ -515,6 +516,7 @@ acpi_os_schedule_exec (
ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Call to kernel_thread() failed.\n"));
acpi_os_free(dpc);
}
return_VOID;
}
acpi_status
......@@ -531,7 +533,7 @@ acpi_os_queue_for_execution(
ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Scheduling function [%p(%p)] for deferred execution.\n", function, context));
if (!function)
return AE_BAD_PARAMETER;
return_ACPI_STATUS (AE_BAD_PARAMETER);
/*
* Queue via DPC:
......@@ -554,7 +556,7 @@ acpi_os_queue_for_execution(
*/
dpc = kmalloc(sizeof(ACPI_OS_DPC), GFP_ATOMIC);
if (!dpc)
return AE_NO_MEMORY;
return_ACPI_STATUS (AE_NO_MEMORY);
dpc->function = function;
dpc->context = context;
......@@ -578,7 +580,7 @@ acpi_os_queue_for_execution(
*/
dpc = kmalloc(sizeof(ACPI_OS_DPC), GFP_KERNEL);
if (!dpc)
return AE_NO_MEMORY;
return_ACPI_STATUS (AE_NO_MEMORY);
dpc->function = function;
dpc->context = context;
......@@ -587,7 +589,7 @@ acpi_os_queue_for_execution(
break;
}
return status;
return_ACPI_STATUS (status);
}
......@@ -603,7 +605,7 @@ acpi_os_create_semaphore(
sem = acpi_os_callocate(sizeof(struct semaphore));
if (!sem)
return AE_NO_MEMORY;
return_ACPI_STATUS (AE_NO_MEMORY);
sema_init(sem, initial_units);
......@@ -611,7 +613,7 @@ acpi_os_create_semaphore(
ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Creating semaphore[%p|%d].\n", *handle, initial_units));
return AE_OK;
return_ACPI_STATUS (AE_OK);
}
......@@ -631,13 +633,13 @@ acpi_os_delete_semaphore(
ACPI_FUNCTION_TRACE ("os_delete_semaphore");
if (!sem)
return AE_BAD_PARAMETER;
return_ACPI_STATUS (AE_BAD_PARAMETER);
ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Deleting semaphore[%p].\n", handle));
acpi_os_free(sem); sem = NULL;
return AE_OK;
return_ACPI_STATUS (AE_OK);
}
......@@ -663,10 +665,10 @@ acpi_os_wait_semaphore(
ACPI_FUNCTION_TRACE ("os_wait_semaphore");
if (!sem || (units < 1))
return AE_BAD_PARAMETER;
return_ACPI_STATUS (AE_BAD_PARAMETER);
if (units > 1)
return AE_SUPPORT;
return_ACPI_STATUS (AE_SUPPORT);
ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Waiting for semaphore[%p|%d|%d]\n", handle, units, timeout));
......@@ -724,7 +726,7 @@ acpi_os_wait_semaphore(
ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Acquired semaphore[%p|%d|%d]\n", handle, units, timeout));
}
return status;
return_ACPI_STATUS (status);
}
......@@ -741,16 +743,16 @@ acpi_os_signal_semaphore(
ACPI_FUNCTION_TRACE ("os_signal_semaphore");
if (!sem || (units < 1))
return AE_BAD_PARAMETER;
return_ACPI_STATUS (AE_BAD_PARAMETER);
if (units > 1)
return AE_SUPPORT;
return_ACPI_STATUS (AE_SUPPORT);
ACPI_DEBUG_PRINT ((ACPI_DB_INFO, "Signaling semaphore[%p|%d]\n", handle, units));
up(sem);
return AE_OK;
return_ACPI_STATUS (AE_OK);
}
u32
......
/*
* acpi_pci_link.c - ACPI PCI Interrupt Link Device Driver ($Revision: 19 $)
* acpi_pci_link.c - ACPI PCI Interrupt Link Device Driver ($Revision: 22 $)
*
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
......@@ -92,35 +92,23 @@ struct acpi_pci_link {
-------------------------------------------------------------------------- */
static int
acpi_pci_link_get_current (
acpi_pci_link_get_possible (
struct acpi_pci_link *link)
{
int result = 0;
int result = 0;
acpi_status status = AE_OK;
acpi_buffer buffer = {0, NULL};
acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
acpi_resource *resource = NULL;
int i = 0;
ACPI_FUNCTION_TRACE("acpi_pci_link_get_current");
ACPI_FUNCTION_TRACE("acpi_pci_link_get_possible");
if (!link || !link->handle)
if (!link)
return_VALUE(-EINVAL);
link->irq.active = 0;
status = acpi_get_current_resources(link->handle, &buffer);
if (status != AE_BUFFER_OVERFLOW) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _CRS\n"));
return_VALUE(-ENODEV);
}
buffer.pointer = kmalloc(buffer.length, GFP_KERNEL);
if (!buffer.pointer)
return_VALUE(-ENOMEM);
memset(buffer.pointer, 0, buffer.length);
status = acpi_get_current_resources(link->handle, &buffer);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _CRS\n"));
status = acpi_get_possible_resources(link->handle, &buffer);
if (ACPI_FAILURE(status) || !buffer.pointer) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRS\n"));
result = -ENODEV;
goto end;
}
......@@ -131,69 +119,84 @@ acpi_pci_link_get_current (
case ACPI_RSTYPE_IRQ:
{
acpi_resource_irq *p = &resource->data.irq;
if (p->number_of_interrupts > 0)
link->irq.active = p->interrupts[0];
else {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Blank IRQ resource\n"));
if (!p || !p->number_of_interrupts) {
ACPI_DEBUG_PRINT((ACPI_DB_WARN,
"Blank IRQ resource\n"));
result = -ENODEV;
goto end;
}
for (i = 0; (i<p->number_of_interrupts && i<ACPI_PCI_LINK_MAX_IRQS); i++) {
link->irq.possible[i] = p->interrupts[i];
link->irq.possible_count++;
}
link->irq.flags.trigger = p->edge_level;
link->irq.flags.polarity = p->active_high_low;
link->irq.flags.shareable = p->shared_exclusive;
break;
}
case ACPI_RSTYPE_EXT_IRQ:
{
acpi_resource_ext_irq *p = &resource->data.extended_irq;
if (p->number_of_interrupts > 0)
link->irq.active = p->interrupts[0];
else {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Blank IRQ resource\n"));
if (!p || !p->number_of_interrupts) {
ACPI_DEBUG_PRINT((ACPI_DB_WARN,
"Blank IRQ resource\n"));
result = -ENODEV;
goto end;
}
for (i = 0; (i<p->number_of_interrupts && i<ACPI_PCI_LINK_MAX_IRQS); i++) {
link->irq.possible[i] = p->interrupts[i];
link->irq.possible_count++;
}
link->irq.flags.trigger = p->edge_level;
link->irq.flags.polarity = p->active_high_low;
link->irq.flags.shareable = p->shared_exclusive;
break;
}
default:
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"First resource is not an IRQ entry\n"));
"Resource is not an IRQ entry\n"));
result = -ENODEV;
goto end;
break;
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Found %d possible IRQs\n", link->irq.possible_count));
end:
kfree(buffer.pointer);
return_VALUE(0);
return_VALUE(result);
}
static int
acpi_pci_link_get_possible (
acpi_pci_link_get_current (
struct acpi_pci_link *link)
{
int result = 0;
int result = 0;
acpi_status status = AE_OK;
acpi_buffer buffer = {0, NULL};
acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
acpi_resource *resource = NULL;
int i = 0;
ACPI_FUNCTION_TRACE("acpi_pci_link_get_possible");
ACPI_FUNCTION_TRACE("acpi_pci_link_get_current");
if (!link)
if (!link || !link->handle)
return_VALUE(-EINVAL);
status = acpi_get_possible_resources(link->handle, &buffer);
if (status != AE_BUFFER_OVERFLOW) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRS\n"));
return_VALUE(-ENODEV);
}
buffer.pointer = kmalloc(buffer.length, GFP_KERNEL);
if (!buffer.pointer)
return_VALUE(-ENOMEM);
memset(buffer.pointer, 0, buffer.length);
link->irq.active = 0;
status = acpi_get_possible_resources(link->handle, &buffer);
status = acpi_get_current_resources(link->handle, &buffer);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PRS\n"));
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _CRS\n"));
result = -ENODEV;
goto end;
}
......@@ -205,20 +208,14 @@ acpi_pci_link_get_possible (
{
acpi_resource_irq *p = &resource->data.irq;
for (i = 0; (i<p->number_of_interrupts && i<ACPI_PCI_LINK_MAX_IRQS); i++) {
link->irq.possible[i] = p->interrupts[i];
link->irq.possible_count++;
}
if (!p->number_of_interrupts) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Blank IRQ resource\n"));
if (!p || !p->number_of_interrupts) {
ACPI_DEBUG_PRINT((ACPI_DB_WARN,
"Blank IRQ resource\n"));
result = -ENODEV;
goto end;
}
link->irq.flags.trigger = p->edge_level;
link->irq.flags.polarity = p->active_high_low;
link->irq.flags.shareable = p->shared_exclusive;
link->irq.active = p->interrupts[0];
break;
}
......@@ -226,32 +223,36 @@ acpi_pci_link_get_possible (
{
acpi_resource_ext_irq *p = &resource->data.extended_irq;
for (i = 0; (i<p->number_of_interrupts && i<ACPI_PCI_LINK_MAX_IRQS); i++) {
link->irq.possible[i] = p->interrupts[i];
link->irq.possible_count++;
}
if (!p->number_of_interrupts) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Blank IRQ resource\n"));
if (!p || !p->number_of_interrupts) {
ACPI_DEBUG_PRINT((ACPI_DB_WARN,
"Blank IRQ resource\n"));
result = -ENODEV;
goto end;
}
link->irq.flags.trigger = p->edge_level;
link->irq.flags.polarity = p->active_high_low;
link->irq.flags.shareable = p->shared_exclusive;
link->irq.active = p->interrupts[0];
break;
}
default:
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"First resource is not an IRQ entry\n"));
"Resource is not an IRQ entry\n"));
break;
}
if (!link->irq.active) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Invalid IRQ %d\n", link->irq.active));
result = -ENODEV;
}
end:
kfree(buffer.pointer);
if (0 == result)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link at IRQ %d \n",
link->irq.active));
return_VALUE(result);
}
......@@ -259,7 +260,7 @@ acpi_pci_link_get_possible (
static int
acpi_pci_link_set (
struct acpi_pci_link *link,
u32 irq)
int irq)
{
acpi_status status = AE_OK;
struct {
......@@ -290,6 +291,8 @@ acpi_pci_link_set (
return_VALUE(-ENODEV);
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Set IRQ %d\n", irq));
return_VALUE(0);
}
......@@ -328,8 +331,10 @@ acpi_pci_link_get_irq (
return_VALUE(-ENODEV);
}
if (!link->irq.flags.valid)
if (!link->irq.flags.valid) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link IRQ invalid\n"));
return_VALUE(-ENODEV);
}
/* TBD: Support multiple index (IRQ) entries per Link Device */
if (0 != entry->source.index) {
......@@ -361,7 +366,7 @@ acpi_pci_link_set_irq (
if (!entry || !entry->source.handle || !irq)
return_VALUE(-EINVAL);
/* TBD: Support multiple index values (not just first). */
/* TBD: Support multiple index (IRQ) entries per Link Device */
if (0 != entry->source.index) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Unsupported resource index [%d]\n",
......@@ -386,7 +391,8 @@ acpi_pci_link_set_irq (
/* Is the target IRQ the same as the currently enabled IRQ? */
if (link->irq.flags.enabled && (irq == link->irq.active)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link IRQ already at target\n"));
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Link already at IRQ %d\n",
irq));
return_VALUE(0);
}
......@@ -413,6 +419,85 @@ acpi_pci_link_set_irq (
}
static int
acpi_pci_link_enable (
struct acpi_device *device,
struct acpi_pci_link *link)
{
int result = -ENODEV;
ACPI_FUNCTION_TRACE("acpi_pci_link_enable");
if (!device || !link)
return_VALUE(-EINVAL);
result = acpi_pci_link_get_possible(link);
if (0 != result)
return_VALUE(result);
result = acpi_bus_get_status(device);
if (0 != result) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to read status\n"));
return_VALUE(-ENODEV);
}
/*
* If this link device isn't enabled (_STA bit 1) then we enable it
* by setting an IRQ.
*/
if (!device->status.enabled) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Attempting to enable at IRQ [%d]\n",
link->irq.possible[0]));
result = acpi_pci_link_set(link, link->irq.possible[0]);
if (0 != result)
return_VALUE(result);
result = acpi_bus_get_status(device);
if (0 != result) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Unable to read status\n"));
return_VALUE(-ENODEV);
}
if (!device->status.enabled) {
ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Enable failed\n"));
return_VALUE(-ENODEV);
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Link enabled at IRQ %d\n",
link->irq.possible[0]));
}
/*
* Now we get the current IRQ just to make sure everything is kosher.
*/
result = acpi_pci_link_get_current(link);
if (0 != result) {
ACPI_DEBUG_PRINT((ACPI_DB_WARN,
"Current IRQ invalid, setting to default\n"));
result = acpi_pci_link_set(link, link->irq.possible[0]);
if (0 != result)
return_VALUE(result);
result = acpi_pci_link_get_current(link);
if (0 != result) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Unable to read current IRQ\n"));
return_VALUE(result);
}
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Using IRQ %d\n", link->irq.active));
link->irq.flags.valid = 1;
return_VALUE(0);
}
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
......@@ -440,34 +525,9 @@ acpi_pci_link_add (
sprintf(acpi_device_class(device), "%s", ACPI_PCI_LINK_CLASS);
acpi_driver_data(device) = link;
result = acpi_pci_link_get_possible(link);
if (0 != result)
return_VALUE(result);
if (!device->status.enabled) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Enabling at IRQ [%d]\n",
link->irq.possible[0]));
result = acpi_pci_link_set(link, link->irq.possible[0]);
if (0 != result)
return_VALUE(result);
result = acpi_bus_get_status(device);
if (0 != result)
return_VALUE(result);
if (!device->status.enabled) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Enable failed\n"));
return_VALUE(-EFAULT);
}
}
result = acpi_pci_link_get_current(link);
result = acpi_pci_link_enable(device, link);
if (0 != result)
return_VALUE(result);
link->irq.flags.valid = 1;
goto end;
printk(PREFIX "%s [%s] (IRQs",
acpi_device_name(device), acpi_device_bid(device));
......@@ -477,7 +537,11 @@ acpi_pci_link_add (
link->irq.possible[i]);
printk(")\n");
return_VALUE(0);
end:
if (0 != result)
kfree(link);
return_VALUE(result);
}
......
/*
* acpi_pci_root.c - ACPI PCI Root Bridge Driver ($Revision: 22 $)
* acpi_pci_root.c - ACPI PCI Root Bridge Driver ($Revision: 30 $)
*
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
......@@ -48,6 +48,7 @@ extern struct pci_ops *pci_root_ops;
static int acpi_pci_root_add (struct acpi_device *device);
static int acpi_pci_root_remove (struct acpi_device *device, int type);
static int acpi_pci_root_bind (struct acpi_device *device);
static struct acpi_driver acpi_pci_root_driver = {
name: ACPI_PCI_ROOT_DRIVER_NAME,
......@@ -56,20 +57,20 @@ static struct acpi_driver acpi_pci_root_driver = {
ops: {
add: acpi_pci_root_add,
remove: acpi_pci_root_remove,
bind: acpi_pci_root_bind,
},
};
struct acpi_pci_root_context {
acpi_handle handle;
struct {
u8 seg; /* Root's segment number */
u8 bus; /* Root's bus number */
u8 sub; /* Max subordinate bus */
} id;
struct pci_bus *bus;
struct acpi_pci_data {
acpi_pci_id id;
struct pci_dev *dev;
};
struct acpi_pci_root {
acpi_handle handle;
struct acpi_pci_data data;
};
struct acpi_prt_list acpi_prts;
......@@ -77,25 +78,33 @@ struct acpi_prt_list acpi_prts;
PCI Routing Table (PRT) Support
-------------------------------------------------------------------------- */
static struct acpi_prt_entry *
static int
acpi_prt_find_entry (
struct pci_dev *dev,
u8 pin)
acpi_pci_id *id,
u8 pin,
struct acpi_prt_entry **entry)
{
struct acpi_prt_entry *entry = NULL;
struct list_head *node = NULL;
ACPI_FUNCTION_TRACE("acpi_prt_find_entry");
if (!id || !entry)
return_VALUE(-ENODEV);
/* TBD: Locking */
list_for_each(node, &acpi_prts.entries) {
entry = list_entry(node, struct acpi_prt_entry, node);
if ((entry->id.dev == PCI_SLOT(dev->devfn))
&& (entry->id.pin == pin))
return_PTR(entry);
(*entry) = list_entry(node, struct acpi_prt_entry, node);
/* TBD: Include check for segment when supported by pci_dev */
if ((id->bus == (*entry)->id.bus)
&& (id->device == (*entry)->id.dev)
&& (pin == (*entry)->id.pin)) {
return_VALUE(0);
}
}
return_PTR(NULL);
(*entry) = NULL;
return_VALUE(-ENODEV);
}
......@@ -107,23 +116,49 @@ acpi_prt_get_irq (
{
int result = 0;
struct acpi_prt_entry *entry = NULL;
acpi_pci_id id = {0, 0, 0, 0};
ACPI_FUNCTION_TRACE("acpi_pci_get_current_irq");
ACPI_FUNCTION_TRACE("acpi_prt_get_irq");
if (!dev || !irq)
return_VALUE(-ENODEV);
entry = acpi_prt_find_entry(dev, pin);
if (!entry)
return_VALUE(-ENODEV);
if (!dev->bus) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Device has invalid 'bus' field\n"));
return_VALUE(-EFAULT);
}
id.segment = 0;
id.bus = dev->bus->number;
id.device = PCI_SLOT(dev->devfn);
id.function = PCI_FUNC(dev->devfn);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Resolving IRQ for %02x:%02x:%02x.%02x[%c]\n",
id.segment, id.bus, id.device, id.function, ('A'+pin)));
result = acpi_prt_find_entry(&id, pin, &entry);
if (0 != result)
return_VALUE(result);
/* Type 1: Dynamic (e.g. PCI Link Device) */
if (entry->source.handle)
result = acpi_pci_link_get_irq(entry, irq);
/* Type 2: Static (e.g. I/O [S]APIC Direct) */
else
*irq = entry->source.index;
else {
if (entry->source.index)
*irq = entry->source.index;
else
result = -ENODEV;
}
if (0 == result)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found IRQ %d\n", *irq));
else
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to reslove IRQ\n"));
return_VALUE(0);
}
......@@ -135,18 +170,32 @@ acpi_prt_set_irq (
int irq)
{
int result = 0;
int i = 0;
int valid = 0;
struct acpi_prt_entry *entry = NULL;
acpi_pci_id id = {0, 0, 0, 0};
ACPI_FUNCTION_TRACE("acpi_pci_set_current_irq");
ACPI_FUNCTION_TRACE("acpi_pci_set_irq");
if (!dev || !irq)
return_VALUE(-EINVAL);
entry = acpi_prt_find_entry(dev, pin);
if (!entry)
return_VALUE(-ENODEV);
if (!dev->bus) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Device has invalid 'bus' field\n"));
return_VALUE(-EFAULT);
}
id.segment = 0;
id.bus = dev->bus->number;
id.device = PCI_SLOT(dev->devfn);
id.function = PCI_FUNC(dev->devfn);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Setting %02x:%02x:%02x.%02x[%c] to IRQ%d\n",
id.segment, id.bus, id.device, id.function, ('A'+pin), irq));
result = acpi_prt_find_entry(&id, pin, &entry);
if (0 != result)
return_VALUE(result);
/* Type 1: Dynamic (e.g. PCI Link Device) */
if (entry->source.handle)
......@@ -155,6 +204,11 @@ acpi_prt_set_irq (
else
result = -EFAULT;
if (0 == result)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "IRQ set\n"));
else
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to set IRQ\n"));
return_VALUE(result);
}
......@@ -212,9 +266,9 @@ acpi_prt_add_entry (
* namespace).
*/
printk(KERN_INFO " %02X:%02X:%02X[%c] -> %s[%d]\n",
ACPI_DEBUG_PRINT_RAW((ACPI_DB_OK, " %02X:%02X:%02X[%c] -> %s[%d]\n",
entry->id.seg, entry->id.bus, entry->id.dev,
('A' + entry->id.pin), prt->source, entry->source.index);
('A' + entry->id.pin), prt->source, entry->source.index));
/* TBD: Acquire/release lock */
list_add_tail(&entry->node, &acpi_prts.entries);
......@@ -225,57 +279,23 @@ acpi_prt_add_entry (
}
static acpi_status
acpi_prt_callback (
acpi_handle handle,
u32 nesting_level,
void *context,
void **return_value)
static int
acpi_prt_parse (
acpi_handle handle,
u8 seg,
u8 bus)
{
acpi_status status = AE_OK;
acpi_handle prt_handle = NULL;
char pathname[PATHNAME_MAX] = {0};
acpi_buffer buffer = {0, NULL};
acpi_pci_routing_table *prt = NULL;
unsigned long sta = 0;
struct acpi_pci_root_context *root = (struct acpi_pci_root_context *) context;
u8 bus_number = 0;
ACPI_FUNCTION_TRACE("acpi_prt_callback");
if (!root)
return_VALUE(AE_BAD_PARAMETER);
status = acpi_get_handle(handle, METHOD_NAME__PRT, &prt_handle);
if (ACPI_FAILURE(status))
return_VALUE(AE_OK);
ACPI_FUNCTION_TRACE("acpi_prt_parse");
buffer.length = sizeof(pathname);
buffer.pointer = pathname;
acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer);
/*
* Evalute _STA to see if the device containing this _PRT is present.
*/
status = acpi_evaluate_integer(handle, METHOD_NAME__STA, NULL, &sta);
switch (status) {
case AE_OK:
if (!(sta & 0x01)) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Found _PRT but device [%s] not present\n",
pathname));
return_VALUE(AE_OK);
}
break;
case AE_NOT_FOUND:
/* assume present */
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Error evaluating %s._STA [%s]\n",
pathname, acpi_format_exception(status)));
return_VALUE(status);
}
printk(KERN_INFO PREFIX "%s [%s._PRT]\n", ACPI_PCI_PRT_DEVICE_NAME,
pathname);
......@@ -287,9 +307,10 @@ acpi_prt_callback (
buffer.pointer = NULL;
status = acpi_get_irq_routing_table(handle, &buffer);
if (status != AE_BUFFER_OVERFLOW) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Error evaluating _PRT [%s]\n",
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Error evaluating _PRT [%s]\n",
acpi_format_exception(status)));
return_VALUE(status);
return_VALUE(-ENODEV);
}
prt = kmalloc(buffer.length, GFP_KERNEL);
......@@ -300,144 +321,401 @@ acpi_prt_callback (
status = acpi_get_irq_routing_table(handle, &buffer);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Error evaluating _PRT [%s]\n",
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Error evaluating _PRT [%s]\n",
acpi_format_exception(status)));
kfree(buffer.pointer);
return_VALUE(status);
}
if (root->handle == handle)
bus_number = root->id.bus;
else {
ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Need to get subordinate bus number!\n"));
/* get the bus number for this device */
return_VALUE(-ENODEV);
}
while (prt && (prt->length > 0)) {
acpi_prt_add_entry(handle, root->id.seg, bus_number, prt);
acpi_prt_add_entry(handle, seg, bus, prt);
prt = (acpi_pci_routing_table*)((unsigned long)prt + prt->length);
}
return_VALUE(AE_OK);
return_VALUE(0);
}
/* --------------------------------------------------------------------------
Driver Interface
PCI Device Binding
-------------------------------------------------------------------------- */
int
acpi_pci_root_add (
static void
acpi_pci_data_handler (
acpi_handle handle,
u32 function,
void *context)
{
ACPI_FUNCTION_TRACE("acpi_pci_data_handler");
/* TBD: Anything we need to do here? */
return_VOID;
}
/**
* acpi_os_get_pci_id
* ------------------
* This function gets used by the ACPI Interpreter (a.k.a. Core Subsystem)
* to resolve PCI information for ACPI-PCI devices defined in the namespace.
*/
acpi_status
acpi_os_get_pci_id (
acpi_handle handle,
acpi_pci_id *id)
{
int result = 0;
acpi_status status = AE_OK;
struct acpi_device *device = NULL;
struct acpi_pci_data *data = NULL;
ACPI_FUNCTION_TRACE("acpi_os_get_pci_id");
if (!id)
return_ACPI_STATUS(AE_BAD_PARAMETER);
result = acpi_bus_get_device(handle, &device);
if (0 != result) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Invalid ACPI Bus context for device %s\n",
acpi_device_bid(device)));
return_ACPI_STATUS(AE_NOT_EXIST);
}
status = acpi_get_data(handle, acpi_pci_data_handler, (void**) &data);
if (ACPI_FAILURE(status) || !data || !data->dev) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Invalid ACPI-PCI context for device %s\n",
acpi_device_bid(device)));
return_ACPI_STATUS(status);
}
id->segment = data->id.segment;
id->bus = data->id.bus;
id->device = data->id.device;
id->function = data->id.function;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Device %s has PCI address %02x:%02x:%02x.%02x\n",
acpi_device_bid(device), id->segment, id->bus,
id->device, id->function));
return_ACPI_STATUS(AE_OK);
}
static int
acpi_pci_root_bind (
struct acpi_device *device)
{
int result = 0;
acpi_status status = AE_OK;
struct acpi_pci_root_context *context = NULL;
unsigned long temp = 0;
struct acpi_pci_data *data = NULL;
struct acpi_pci_data *parent_data = NULL;
acpi_handle handle = NULL;
ACPI_FUNCTION_TRACE("acpi_pci_root_add");
ACPI_FUNCTION_TRACE("acpi_pci_root_bind");
if (!device)
if (!device || !device->parent)
return_VALUE(-EINVAL);
context = kmalloc(sizeof(struct acpi_pci_root_context), GFP_KERNEL);
if (!context)
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Attempting to bind PCI device %s.%s\n",
acpi_device_bid(device->parent), acpi_device_bid(device)));
data = kmalloc(sizeof(struct acpi_pci_data), GFP_KERNEL);
if (!data)
return_VALUE(-ENOMEM);
memset(context, 0, sizeof(struct acpi_pci_root_context));
memset(data, 0, sizeof(struct acpi_pci_data));
context->handle = device->handle;
sprintf(acpi_device_name(device), "%s", ACPI_PCI_ROOT_DEVICE_NAME);
sprintf(acpi_device_class(device), "%s", ACPI_PCI_ROOT_CLASS);
acpi_driver_data(device) = context;
/*
* Segment & Bus
* -------------
* These are obtained via the parent device's ACPI-PCI context..
* Note that PCI root bridge devices don't have a 'dev->subordinate'.
*/
status = acpi_get_data(device->parent->handle, acpi_pci_data_handler,
(void**) &parent_data);
if (ACPI_FAILURE(status) || !parent_data || !parent_data->dev) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Invalid ACPI-PCI context for parent device %s\n",
acpi_device_bid(device->parent)));
result = -ENODEV;
goto end;
}
status = acpi_evaluate_integer(context->handle, METHOD_NAME__SEG,
NULL, &temp);
if (ACPI_SUCCESS(status))
context->id.seg = temp;
else
context->id.seg = 0;
data->id.segment = parent_data->id.segment;
status = acpi_evaluate_integer(context->handle, METHOD_NAME__BBN,
NULL, &temp);
if (ACPI_SUCCESS(status))
context->id.bus = temp;
else
context->id.bus = 0;
if (parent_data->dev->subordinate) /* e.g. PCI-PCI bridge */
data->id.bus = parent_data->dev->subordinate->number;
else if (parent_data->dev->bus) /* PCI root bridge */
data->id.bus = parent_data->dev->bus->number;
else {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Parent device %s is not a PCI bridge\n",
acpi_device_bid(device->parent)));
result = -ENODEV;
goto end;
}
/* TBD: Evaluate _CRS for bus range of child P2P (bus min/max/len) */
/*
* Device & Function
* -----------------
* These are simply obtained from the device's _ADR method. Note
* that a value of zero is valid.
*/
data->id.device = device->pnp.bus_address >> 16;
data->id.function = device->pnp.bus_address & 0xFFFF;
printk(KERN_INFO PREFIX "%s [%s] (%02x:%02x)\n",
acpi_device_name(device), acpi_device_bid(device),
context->id.seg, context->id.bus);
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Binding device %s.%s to %02x:%02x:%02x.%02x\n",
acpi_device_bid(device->parent), acpi_device_bid(device),
data->id.segment, data->id.bus, data->id.device,
data->id.function));
/*
* Locate PCI Device
* -----------------
* Locate matching device in PCI namespace. If it doesn't exist
* this typically means that the device isn't currently inserted
* (e.g. docking station, port replicator, etc.).
*/
data->dev = pci_find_slot(data->id.bus,
PCI_DEVFN(data->id.device, data->id.function));
if (!data->dev) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Device %02x:%02x:%02x.%02x not present in PCI namespace\n",
data->id.segment, data->id.bus,
data->id.device, data->id.function));
result = -ENODEV;
goto end;
}
if (!data->dev->bus) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Device %02x:%02x:%02x.%02x has invalid 'bus' field\n",
data->id.segment, data->id.bus,
data->id.device, data->id.function));
result = -ENODEV;
goto end;
}
/*
* Scan all devices on this root bridge. Note that this must occur
* now to get the correct bus number assignments for subordinate
* PCI-PCI bridges.
* Attach ACPI-PCI Context
* -----------------------
* Thus binding the ACPI and PCI devices.
*/
pci_scan_bus(context->id.bus, pci_root_ops, NULL);
status = acpi_attach_data(device->handle, acpi_pci_data_handler, data);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Unable to attach ACPI-PCI context to device %s\n",
acpi_device_bid(device)));
result = -ENODEV;
goto end;
}
/* Evaluate _PRT for this root bridge. */
acpi_prt_callback(context->handle, 0, context, NULL);
/*
* PCI Bridge?
* -----------
* If so, install the 'bind' function to facilitate callbacks for
* all of its children.
*/
if (data->dev->subordinate)
device->ops.bind = acpi_pci_root_bind;
/* Evaluate all subordinate _PRTs. */
acpi_walk_namespace(ACPI_TYPE_DEVICE, context->handle, ACPI_UINT32_MAX,
acpi_prt_callback, context, NULL);
/*
* PCI Routing Table
* -----------------
* Evaluate and parse _PRT, if exists. This code is independent of
* PCI bridges (above) to allow parsing of _PRT objects within the
* scope of non-bridge devices. Note that _PRTs within the scope of
* a PCI bridge assume the bridge's subordinate bus number.
*
* TBD: Can _PRTs exist within the scope of non-bridge PCI devices?
*/
status = acpi_get_handle(device->handle, METHOD_NAME__PRT, &handle);
if (ACPI_SUCCESS(status)) {
if (data->dev->subordinate) /* PCI-PCI bridge */
acpi_prt_parse(device->handle, data->id.segment,
data->dev->subordinate->number);
else /* non-bridge PCI device */
acpi_prt_parse(device->handle, data->id.segment,
data->id.bus);
}
return_VALUE(0);
end:
if (0 != result)
kfree(data);
return_VALUE(result);
}
int
acpi_pci_root_remove (
struct acpi_device *device,
int type)
/* --------------------------------------------------------------------------
Driver Interface
-------------------------------------------------------------------------- */
static int
acpi_pci_root_add (
struct acpi_device *device)
{
struct acpi_pci_dev_context *context = NULL;
int result = 0;
struct acpi_pci_root *root = NULL;
acpi_status status = AE_OK;
unsigned long value = 0;
ACPI_FUNCTION_TRACE("acpi_pci_root_add");
if (!device)
return -EINVAL;
return_VALUE(-EINVAL);
if (device->driver_data)
/* Root bridge */
kfree(device->driver_data);
else {
/* Standard PCI device */
context = acpi_driver_data(device);
if (context)
kfree(context);
root = kmalloc(sizeof(struct acpi_pci_root), GFP_KERNEL);
if (!root)
return_VALUE(-ENOMEM);
memset(root, 0, sizeof(struct acpi_pci_root));
root->handle = device->handle;
sprintf(acpi_device_name(device), "%s", ACPI_PCI_ROOT_DEVICE_NAME);
sprintf(acpi_device_class(device), "%s", ACPI_PCI_ROOT_CLASS);
acpi_driver_data(device) = root;
/*
* TBD: Doesn't the bus driver automatically set this?
*/
device->ops.bind = acpi_pci_root_bind;
/*
* Segment
* -------
* Obtained via _SEG, if exists, otherwise assumed to be zero (0).
*/
status = acpi_evaluate_integer(root->handle, METHOD_NAME__SEG, NULL,
&value);
switch (status) {
case AE_OK:
root->data.id.segment = (u16) value;
break;
case AE_NOT_FOUND:
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Assuming segment 0 (no _SEG)\n"));
root->data.id.segment = 0;
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _SEG\n"));
result = -ENODEV;
goto end;
}
return 0;
}
/*
* Bus
* ---
* Obtained via _BBN, if exists, otherwise assumed to be zero (0).
*/
status = acpi_evaluate_integer(root->handle, METHOD_NAME__BBN, NULL,
&value);
switch (status) {
case AE_OK:
root->data.id.bus = (u16) value;
break;
case AE_NOT_FOUND:
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Assuming bus 0 (no _BBN)\n"));
root->data.id.bus = 0;
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _BBN\n"));
result = -ENODEV;
goto end;
}
/*
* Device & Function
* -----------------
* Obtained from _ADR (which has already been evaluated for us).
*/
root->data.id.device = device->pnp.bus_address >> 16;
root->data.id.function = device->pnp.bus_address & 0xFFFF;
int __init
acpi_pci_irq_init (void)
{
int result = 0;
acpi_status status = AE_OK;
acpi_object arg = {ACPI_TYPE_INTEGER};
acpi_object_list arg_list = {1, &arg};
int irq_model = 0;
/*
* TBD: Evaluate _CRS to get root bridge resources
* TBD: Need PCI interface for enumeration/configuration of roots.
*/
ACPI_FUNCTION_TRACE("acpi_pci_irq_init");
printk(KERN_INFO PREFIX "%s [%s] (%02x:%02x:%02x.%02x)\n",
acpi_device_name(device), acpi_device_bid(device),
root->data.id.segment, root->data.id.bus,
root->data.id.device, root->data.id.function);
/*
* Scan the Root Bridge
* --------------------
* Must do this prior to any attempt to bind the root device, as the
* PCI namespace does not get created until this call is made (and
* thus the root bridge's pci_dev does not exist).
*/
pci_scan_bus(root->data.id.bus, pci_root_ops, NULL);
/*
* Let the system know what interrupt model we are using by
* evaluating the \_PIC object, if exists.
* Locate PCI Device
* -----------------
* Locate the matching PCI root bridge device in the PCI namespace.
*/
root->data.dev = pci_find_slot(root->data.id.bus,
PCI_DEVFN(root->data.id.device, root->data.id.function));
if (!root->data.dev) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Device %02x:%02x:%02x.%02x not present\n",
root->data.id.segment, root->data.id.bus,
root->data.id.device, root->data.id.function));
result = -ENODEV;
goto end;
}
result = acpi_get_interrupt_model(&irq_model);
/*
* Attach ACPI-PCI Context
* -----------------------
* Thus binding the ACPI and PCI devices.
*/
status = acpi_attach_data(root->handle, acpi_pci_data_handler,
&root->data);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Unable to attach ACPI-PCI context to device %s\n",
acpi_device_bid(device)));
result = -ENODEV;
goto end;
}
/*
* PCI Routing Table
* -----------------
* Evaluate and parse _PRT, if exists. Note that root bridges
* must have a _PRT (optional for subordinate bridges).
*/
result = acpi_prt_parse(device->handle, root->data.id.segment,
root->data.id.bus);
end:
if (0 != result)
return_VALUE(result);
kfree(root);
arg.integer.value = irq_model;
return_VALUE(result);
}
status = acpi_evaluate_object(NULL, "\\_PIC", &arg_list, NULL);
if (ACPI_FAILURE(status) && (status != AE_NOT_FOUND)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PIC\n"));
return_VALUE(-ENODEV);
}
static int
acpi_pci_root_remove (
struct acpi_device *device,
int type)
{
struct acpi_pci_root *root = NULL;
ACPI_FUNCTION_TRACE("acpi_pci_root_remove");
if (!device || !acpi_driver_data(device))
return_VALUE(-EINVAL);
root = (struct acpi_pci_root *) acpi_driver_data(device);
kfree(root);
return_VALUE(0);
}
......@@ -446,17 +724,11 @@ acpi_pci_irq_init (void)
int __init
acpi_pci_root_init (void)
{
int result = 0;
ACPI_FUNCTION_TRACE("acpi_pci_root_init");
acpi_prts.count = 0;
INIT_LIST_HEAD(&acpi_prts.entries);
result = acpi_pci_irq_init();
if (0 != result)
return_VALUE(result);
if (0 > acpi_bus_register_driver(&acpi_pci_root_driver))
return_VALUE(-ENODEV);
......@@ -470,5 +742,6 @@ acpi_pci_root_exit (void)
ACPI_FUNCTION_TRACE("acpi_pci_root_exit");
acpi_bus_unregister_driver(&acpi_pci_root_driver);
}
return_VOID;
}
/*
* acpi_processor.c - ACPI Processor Driver ($Revision: 50 $)
* acpi_processor.c - ACPI Processor Driver ($Revision: 57 $)
*
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
......@@ -23,16 +23,12 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* TBD:
* 1. Make # power/performance states dynamic.
* 2. Includes support for _real_ performance states (not just throttle).
* 3. Support duty_cycle values that span bit 4.
* 4. Optimize by having scheduler determine business instead of
* having us try to calculate it here.
* 5. Need C1 timing -- must modify kernel (IRQ handler) to get this.
* 6. Convert time values to ticks (initially) to avoid having to do
* the math (acpi_get_timer_duration).
* 7. What is a good default value for the OS busy_metric?
* 8. Support both thermal and power limits.
* 9. Resolve PIIX4 BMISX errata issue (getting an I/O port value of 0).
* 2. Support duty_cycle values that span bit 4.
* 3. Optimize by having scheduler determine business instead of
* having us try to calculate it here.
* 4. Need C1 timing -- must modify kernel (IRQ handler) to get this.
* 5. Convert time values to ticks (initially) to avoid having to do
* the math (acpi_get_timer_duration).
*/
#include <linux/kernel.h>
......@@ -43,6 +39,7 @@
#include <linux/pm.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/delay.h>
#include "acpi_bus.h"
#include "acpi_drivers.h"
......@@ -56,20 +53,22 @@ MODULE_LICENSE("GPL");
#define PREFIX "ACPI: "
#define ACPI_PROCESSOR_BUSY_METRIC 10
#define ACPI_PROCESSOR_MAX_POWER ACPI_C_STATE_COUNT
#define ACPI_PROCESSOR_MAX_C2_LATENCY 100
#define ACPI_PROCESSOR_MAX_C3_LATENCY 1000
#define ACPI_PROCESSOR_MAX_PERFORMANCE 4
#define ACPI_PROCESSOR_MAX_PERFORMANCE 8
#define ACPI_PROCESSOR_MAX_THROTTLING 16
#define ACPI_PROCESSOR_MAX_THROTTLE 500 /* 50% */
#define ACPI_PROCESSOR_MAX_THROTTLE 250 /* 25% */
#define ACPI_PROCESSOR_MAX_DUTY_WIDTH 4
const u32 POWER_OF_2[] = {1,2,4,8,16,32,64};
#define ACPI_PROCESSOR_MAX_LIMIT 20
#define ACPI_PROCESSOR_LIMIT_USER 0
#define ACPI_PROCESSOR_LIMIT_THERMAL 1
static int acpi_processor_add (struct acpi_device *device);
static int acpi_processor_remove (struct acpi_device *device, int type);
......@@ -110,24 +109,35 @@ struct acpi_processor_power {
int state;
int default_state;
u32 bm_activity;
u32 busy_metric;
struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER];
};
/* Performance Management */
struct acpi_pct_register {
u8 descriptor;
u16 length;
u8 space_id;
u8 bit_width;
u8 bit_offset;
u8 reserved;
u64 address;
} __attribute__ ((packed));
struct acpi_processor_px {
u8 valid;
u32 core_frequency;
u32 power;
u32 transition_latency;
u32 bus_master_latency;
u32 control;
u32 status;
acpi_integer core_frequency; /* megahertz */
acpi_integer power; /* milliWatts */
acpi_integer transition_latency; /* microseconds */
acpi_integer bus_master_latency; /* microseconds */
acpi_integer control; /* control value */
acpi_integer status; /* success indicator */
};
struct acpi_processor_performance {
int state;
int platform_limit;
u16 control_register;
u16 status_register;
int state_count;
struct acpi_processor_px states[ACPI_PROCESSOR_MAX_PERFORMANCE];
};
......@@ -136,7 +146,6 @@ struct acpi_processor_performance {
/* Throttling Control */
struct acpi_processor_tx {
u8 valid;
u16 power;
u16 performance;
};
......@@ -153,37 +162,25 @@ struct acpi_processor_throttling {
/* Limit Interface */
struct acpi_processor_lx {
u8 valid;
u16 performance;
int px;
int tx;
int px; /* performace state */
int tx; /* throttle level */
};
struct acpi_processor_limit {
int state;
int state_count;
struct {
u8 valid;
u16 performance;
int px;
int tx;
} states[ACPI_PROCESSOR_MAX_LIMIT];
struct acpi_processor_lx state; /* current limit */
struct acpi_processor_lx thermal; /* thermal limit */
struct acpi_processor_lx user; /* user limit */
};
struct acpi_processor_flags {
u8 bm_control:1;
u8 power:1;
u8 performance:1;
u8 throttling:1;
u8 limit:1;
u8 reserved:3;
};
struct acpi_processor_errata {
struct {
u8 reverse_throttle;
u32 bmisx;
} piix4;
u8 bm_control:1;
u8 bm_check:1;
u8 reserved:2;
};
struct acpi_processor {
......@@ -191,15 +188,25 @@ struct acpi_processor {
u32 acpi_id;
u32 id;
struct acpi_processor_flags flags;
struct acpi_processor_errata errata;
struct acpi_processor_power power;
struct acpi_processor_performance performance;
struct acpi_processor_throttling throttling;
struct acpi_processor_limit limit;
};
struct acpi_processor_errata {
u8 smp;
struct {
u8 throttle:1;
u8 fdma:1;
u8 reserved:6;
u32 bmisx;
} piix4;
};
static u8 acpi_processor_smp = 0;
static struct acpi_processor *processors[NR_CPUS];
static struct acpi_processor_errata errata;
static void (*pm_idle_save)(void) = NULL;
/* --------------------------------------------------------------------------
......@@ -207,68 +214,138 @@ static u8 acpi_processor_smp = 0;
-------------------------------------------------------------------------- */
int
acpi_processor_get_errata (
struct acpi_processor *pr)
acpi_processor_errata_piix4 (
struct pci_dev *dev)
{
struct pci_dev *dev = NULL;
u8 rev = 0;
u8 value1 = 0;
u8 value2 = 0;
ACPI_FUNCTION_TRACE("acpi_processor_get_errata");
ACPI_FUNCTION_TRACE("acpi_processor_errata_piix4");
if (!pr)
if (!dev)
return_VALUE(-EINVAL);
/*
* PIIX4
* -----
* Note that 'dev' references the PIIX4 ACPI Controller.
*/
dev = pci_find_subsys(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82371AB_3, PCI_ANY_ID, PCI_ANY_ID, dev);
if (dev) {
u8 rev = 0;
pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
pci_read_config_byte(dev, PCI_REVISION_ID, &rev);
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "PIIX4 ACPI rev %d\n", rev));
switch (rev) {
case 0:
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 A-step\n"));
break;
case 1:
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4 B-step\n"));
break;
case 2:
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4E\n"));
break;
case 3:
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found PIIX4M\n"));
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found unknown PIIX4\n"));
break;
}
switch (rev) {
switch (rev) {
case 0: /* PIIX4 A-step */
case 1: /* PIIX4 B-step */
/*
* Workaround for reverse-notation on throttling states
* used by early PIIX4 models.
*/
pr->errata.piix4.reverse_throttle = 1;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Reverse-throttle errata enabled\n"));
case 2: /* PIIX4E */
case 3: /* PIIX4M */
/*
* Workaround for errata #18 "C3 Power State/BMIDE and
* Type-F DMA Livelock" from the July 2001 PIIX4
* specification update. Applies to all PIIX4 models.
*/
/* TBD: Why is the bmisx value always ZERO? */
pr->errata.piix4.bmisx = pci_resource_start(dev, 4);
if (pr->errata.piix4.bmisx)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"BM-IDE errata enabled\n"));
break;
case 0: /* PIIX4 A-step */
case 1: /* PIIX4 B-step */
/*
* See specification changes #13 ("Manual Throttle Duty Cycle")
* and #14 ("Enabling and Disabling Manual Throttle"), plus
* erratum #5 ("STPCLK# Deassertion Time") from the January
* 2002 PIIX4 specification update. Applies to only older
* PIIX4 models.
*/
errata.piix4.throttle = 1;
case 2: /* PIIX4E */
case 3: /* PIIX4M */
/*
* See erratum #18 ("C3 Power State/BMIDE and Type-F DMA
* Livelock") from the January 2002 PIIX4 specification update.
* Applies to all PIIX4 models.
*/
/*
* BM-IDE
* ------
* Find the PIIX4 IDE Controller and get the Bus Master IDE
* Status register address. We'll use this later to read
* each IDE controller's DMA status to make sure we catch all
* DMA activity.
*/
dev = pci_find_subsys(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82371AB,
PCI_ANY_ID, PCI_ANY_ID, NULL);
if (dev)
errata.piix4.bmisx = pci_resource_start(dev, 4);
/*
* Type-F DMA
* ----------
* Find the PIIX4 ISA Controller and read the Motherboard
* DMA controller's status to see if Type-F (Fast) DMA mode
* is enabled (bit 7) on either channel. Note that we'll
* disable C3 support if this is enabled, as some legacy
* devices won't operate well if fast DMA is disabled.
*/
dev = pci_find_subsys(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82371AB_0,
PCI_ANY_ID, PCI_ANY_ID, NULL);
if (dev) {
pci_read_config_byte(dev, 0x76, &value1);
pci_read_config_byte(dev, 0x77, &value2);
if ((value1 & 0x80) || (value2 & 0x80))
errata.piix4.fdma = 1;
}
break;
}
if (errata.piix4.bmisx)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Bus master activity detection (BM-IDE) erratum enabled\n"));
if (errata.piix4.fdma)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Type-F DMA livelock erratum (C3 disabled)\n"));
return_VALUE(0);
}
int
acpi_processor_errata (
struct acpi_processor *pr)
{
int result = 0;
struct pci_dev *dev = NULL;
ACPI_FUNCTION_TRACE("acpi_processor_errata");
if (!pr)
return_VALUE(-EINVAL);
/*
* PIIX4
*/
dev = pci_find_subsys(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_82371AB_3, PCI_ANY_ID, PCI_ANY_ID, NULL);
if (dev)
result = acpi_processor_errata_piix4(dev);
return_VALUE(result);
}
/* --------------------------------------------------------------------------
Power Management
-------------------------------------------------------------------------- */
static struct acpi_processor *acpi_processor_list[NR_CPUS];
static void (*pm_idle_save)(void) = NULL;
static void
acpi_processor_power_activate (
struct acpi_processor *pr,
......@@ -311,9 +388,8 @@ acpi_processor_idle (void)
u32 start_ticks = 0;
u32 end_ticks = 0;
u32 time_elapsed = 0;
static unsigned long last_idle_jiffies = 0;
pr = acpi_processor_list[smp_processor_id()];
pr = processors[smp_processor_id()];
if (!pr)
return;
......@@ -323,55 +399,47 @@ acpi_processor_idle (void)
*/
__cli();
next_state = pr->power.state;
cx = &(pr->power.states[pr->power.state]);
/*
* Check OS Idleness:
* ------------------
* If the OS has been busy (hasn't called the idle handler in a while)
* then automatically demote to the default power state (e.g. C1).
*
* TBD: Optimize by having scheduler determine business instead
* of having us try to calculate it here.
* Check BM Activity
* -----------------
* Check for bus mastering activity (if required), record, and check
* for demotion.
*/
if (pr->power.state != pr->power.default_state) {
if ((jiffies - last_idle_jiffies) >= pr->power.busy_metric) {
next_state = pr->power.default_state;
if (next_state != pr->power.state)
acpi_processor_power_activate(pr, next_state);
}
}
if (pr->flags.bm_check) {
/*
* Log BM Activity:
* ----------------
* Read BM_STS and record its value for later use by C3 policy.
* (Note that we save the BM_STS values for the last 32 cycles).
*/
if (pr->flags.bm_control) {
pr->power.bm_activity <<= 1;
pr->power.bm_activity &= 0xFFFFFFFE;
if (acpi_hw_bit_register_read(ACPI_BITREG_BUS_MASTER_STATUS, ACPI_MTX_DO_NOT_LOCK)) {
pr->power.bm_activity |= 1;
acpi_hw_bit_register_write(ACPI_BITREG_BUS_MASTER_STATUS,
1, ACPI_MTX_DO_NOT_LOCK);
pr->power.bm_activity++;
acpi_hw_bit_register_write(ACPI_BITREG_BUS_MASTER_STATUS, 1, ACPI_MTX_DO_NOT_LOCK);
}
/*
* PIIX4 Errata:
* -------------
* This code is a workaround for errata #18 "C3 Power State/
* BMIDE and Type-F DMA Livelock" from the July '01 PIIX4
* specification update. Note that BM_STS doesn't always
* reflect the true state of bus mastering activity; forcing
* us to manually check the BMIDEA bit of each IDE channel.
* PIIX4 Erratum #18: Note that BM_STS doesn't always reflect
* the true state of bus mastering activity; forcing us to
* manually check the BMIDEA bit of each IDE channel.
*/
else if (pr->errata.piix4.bmisx) {
if ((inb_p(pr->errata.piix4.bmisx + 0x02) & 0x01) ||
(inb_p(pr->errata.piix4.bmisx + 0x0A) & 0x01))
pr->power.bm_activity |= 1;
else if (errata.piix4.bmisx) {
if ((inb_p(errata.piix4.bmisx + 0x02) & 0x01)
|| (inb_p(errata.piix4.bmisx + 0x0A) & 0x01))
pr->power.bm_activity++;
}
/*
* Apply bus mastering demotion policy. Automatically demote
* to avoid a faulty transition. Note that the processor
* won't enter a low-power state during this call (to this
* funciton) but should upon the next.
*/
if (pr->power.bm_activity & cx->demotion.threshold.bm) {
__sti();
next_state = cx->demotion.state;
goto end;
}
}
cx = &(pr->power.states[pr->power.state]);
cx->usage++;
/*
......@@ -416,7 +484,7 @@ acpi_processor_idle (void)
acpi_hw_bit_register_write(ACPI_BITREG_ARB_DISABLE, 1, ACPI_MTX_DO_NOT_LOCK);
/* See how long we're asleep for */
start_ticks = inl(acpi_fadt.Xpm_tmr_blk.address);
/* Invoke C2 */
/* Invoke C3 */
inb(pr->power.states[ACPI_STATE_C3].address);
/* Dummy op - must do something useless after P_LVL3 read */
end_ticks = inl(acpi_fadt.Xpm_tmr_blk.address);
......@@ -439,6 +507,8 @@ acpi_processor_idle (void)
return;
}
next_state = pr->power.state;
/*
* Promotion?
* ----------
......@@ -451,12 +521,16 @@ acpi_processor_idle (void)
cx->promotion.count++;
cx->demotion.count = 0;
if (cx->promotion.count >= cx->promotion.threshold.count) {
if (pr->flags.bm_control) {
if (!(pr->power.bm_activity & cx->promotion.threshold.bm))
if (pr->flags.bm_check) {
if (!(pr->power.bm_activity & cx->promotion.threshold.bm)) {
next_state = cx->promotion.state;
goto end;
}
}
else
else {
next_state = cx->promotion.state;
goto end;
}
}
}
}
......@@ -466,21 +540,20 @@ acpi_processor_idle (void)
* ---------
* Track the number of shorts (time asleep is less than time threshold)
* and demote when the usage threshold is reached. Note that bus
* mastering activity may cause immediate demotions.
* mastering demotions are checked prior to state transitions (above).
*/
if (cx->demotion.state) {
if (time_elapsed < cx->demotion.threshold.time) {
cx->demotion.count++;
cx->promotion.count = 0;
if (cx->demotion.count >= cx->demotion.threshold.count)
next_state = cx->demotion.state;
}
if (pr->flags.bm_control) {
if (pr->power.bm_activity & cx->demotion.threshold.bm)
if (cx->demotion.count >= cx->demotion.threshold.count) {
next_state = cx->demotion.state;
goto end;
}
}
}
end:
/*
* New Cx State?
* -------------
......@@ -490,14 +563,6 @@ acpi_processor_idle (void)
if (next_state != pr->power.state)
acpi_processor_power_activate(pr, next_state);
/*
* Track OS Idleness:
* ------------------
* Record a jiffies timestamp to compute time elapsed between calls
* to the idle handler.
*/
last_idle_jiffies = jiffies;
return;
}
......@@ -520,47 +585,31 @@ acpi_processor_set_power_policy (
if (!pr)
return_VALUE(-EINVAL);
/*
* The Busy Metric is used to determine when the OS has been busy
* and thus when policy should return to using the default Cx state
* (e.g. C1). On Linux we use the number of jiffies (scheduler
* quantums) that transpire between calls to the idle handler.
*
* TBD: What is a good value for the OS busy_metric?
*/
pr->power.busy_metric = 2;
/*
* C0/C1
* -----
*/
if (pr->power.states[ACPI_STATE_C1].valid) {
pr->power.state = ACPI_STATE_C1;
pr->power.default_state = ACPI_STATE_C1;
}
else {
pr->power.state = ACPI_STATE_C0;
pr->power.default_state = ACPI_STATE_C0;
return_VALUE(0);
}
pr->power.state = ACPI_STATE_C1;
pr->power.default_state = ACPI_STATE_C1;
/*
* C1/C2
* -----
* Set the default C1 promotion and C2 demotion policies, where we
* promote from C1 to C2 anytime we're asleep in C1 for longer than
* two times the C2 latency (to amortize cost of transitions). Demote
* from C2 to C1 anytime we're asleep in C2 for less than this time.
* promote from C1 to C2 after several (10) successive C1 transitions,
* as we cannot (currently) measure the time spent in C1. Demote from
* C2 to C1 after experiencing several (3) 'shorts' (time spent in C2
* is less than the C2 transtional latency).
*/
if (pr->power.states[ACPI_STATE_C2].valid) {
pr->power.states[ACPI_STATE_C1].promotion.threshold.count = 10;
pr->power.states[ACPI_STATE_C1].promotion.threshold.time =
(2 * pr->power.states[ACPI_STATE_C2].latency);
pr->power.states[ACPI_STATE_C2].latency;
pr->power.states[ACPI_STATE_C1].promotion.state = ACPI_STATE_C2;
pr->power.states[ACPI_STATE_C2].demotion.threshold.count = 1;
pr->power.states[ACPI_STATE_C2].demotion.threshold.count = 3;
pr->power.states[ACPI_STATE_C2].demotion.threshold.time =
(2 * pr->power.states[ACPI_STATE_C2].latency);
pr->power.states[ACPI_STATE_C2].latency;
pr->power.states[ACPI_STATE_C2].demotion.state = ACPI_STATE_C1;
}
......@@ -576,13 +625,13 @@ acpi_processor_set_power_policy (
(pr->power.states[ACPI_STATE_C3].valid)) {
pr->power.states[ACPI_STATE_C2].promotion.threshold.count = 1;
pr->power.states[ACPI_STATE_C2].promotion.threshold.time =
(2 * pr->power.states[ACPI_STATE_C3].latency);
pr->power.states[ACPI_STATE_C3].latency;
pr->power.states[ACPI_STATE_C2].promotion.threshold.bm = 0x0F;
pr->power.states[ACPI_STATE_C2].promotion.state = ACPI_STATE_C3;
pr->power.states[ACPI_STATE_C3].demotion.threshold.count = 1;
pr->power.states[ACPI_STATE_C3].demotion.threshold.time =
(2 * pr->power.states[ACPI_STATE_C3].latency);
pr->power.states[ACPI_STATE_C3].latency;
pr->power.states[ACPI_STATE_C3].demotion.threshold.bm = 0x0F;
pr->power.states[ACPI_STATE_C3].demotion.state = ACPI_STATE_C2;
}
......@@ -614,7 +663,7 @@ acpi_processor_get_power_info (
* --
* This state exists only as filler in our array.
*/
pr->power.states[ACPI_STATE_C0].valid = TRUE;
pr->power.states[ACPI_STATE_C0].valid = 1;
/*
* C1
......@@ -623,7 +672,7 @@ acpi_processor_get_power_info (
*
* TBD: What about PROC_C1?
*/
pr->power.states[ACPI_STATE_C1].valid = TRUE;
pr->power.states[ACPI_STATE_C1].valid = 1;
/*
* C2
......@@ -633,32 +682,82 @@ acpi_processor_get_power_info (
* TBD: Support for C2 on MP (P_LVL2_UP).
*/
if (pr->power.states[ACPI_STATE_C2].address) {
pr->power.states[ACPI_STATE_C2].latency = acpi_fadt.plvl2_lat;
if (acpi_fadt.plvl2_lat > ACPI_PROCESSOR_MAX_C2_LATENCY)
/*
* C2 latency must be less than or equal to 100 microseconds.
*/
if (acpi_fadt.plvl2_lat >= ACPI_PROCESSOR_MAX_C2_LATENCY)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"C2 latency too large [%d]\n",
acpi_fadt.plvl2_lat));
else if (!acpi_processor_smp)
pr->power.states[ACPI_STATE_C2].valid = TRUE;
/*
* Only support C2 on UP systems (see TBD above).
*/
else if (errata.smp)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"C2 not supported in SMP mode\n"));
/*
* Otherwise we've met all of our C2 requirements.
*/
else
pr->power.states[ACPI_STATE_C2].valid = 1;
}
/*
* C3
* --
* We're (currently) only supporting C3 on UP systems that include
* bus mastering arbitration control. Note that this method of
* maintaining cache coherency (disabling of bus mastering) cannot be
* used on SMP systems, and flushing caches (e.g. WBINVD) is simply
* too costly (at this time).
* TBD: Investigate use of WBINVD on UP/SMP system in absence of
* bm_control.
*/
if (pr->power.states[ACPI_STATE_C3].address) {
pr->power.states[ACPI_STATE_C3].latency = acpi_fadt.plvl3_lat;
if (acpi_fadt.plvl3_lat > ACPI_PROCESSOR_MAX_C3_LATENCY)
/*
* C3 latency must be less than or equal to 1000 microseconds.
*/
if (acpi_fadt.plvl3_lat >= ACPI_PROCESSOR_MAX_C3_LATENCY)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"C3 latency too large [%d]\n",
acpi_fadt.plvl3_lat));
else if (!acpi_processor_smp && pr->flags.bm_control)
/*
* Only support C3 when bus mastering arbitration control
* is present (able to disable bus mastering to maintain
* cache coherency while in C3).
*/
else if (!pr->flags.bm_control)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"C3 support requires bus mastering control\n"));
/*
* Only support C3 on UP systems, as bm_control is only viable
* on a UP system and flushing caches (e.g. WBINVD) is simply
* too costly (at this time).
*/
else if (errata.smp)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"C3 not supported in SMP mode\n"));
/*
* PIIX4 Erratum #18: We don't support C3 when Type-F (fast)
* DMA transfers are used by any ISA device to avoid livelock.
* Note that we could disable Type-F DMA (as recommended by
* the erratum), but this is known to disrupt certain ISA
* devices thus we take the conservative approach.
*/
else if (errata.piix4.fdma) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"C3 not supported on PIIX4 with Type-F DMA\n"));
}
/*
* Otherwise we've met all of our C3 requirements. Enable
* checking of bus mastering status (bm_check) so we can
* use this in our C3 policy.
*/
else {
pr->power.states[ACPI_STATE_C3].valid = 1;
pr->flags.bm_check = 1;
}
}
/*
......@@ -678,7 +777,7 @@ acpi_processor_get_power_info (
* manageable'. Note that there's really no policy involved for
* when only C1 is supported.
*/
if (pr->power.states[ACPI_STATE_C2].valid
if (pr->power.states[ACPI_STATE_C2].valid
|| pr->power.states[ACPI_STATE_C3].valid)
pr->flags.power = 1;
......@@ -690,30 +789,214 @@ acpi_processor_get_power_info (
Performance Management
-------------------------------------------------------------------------- */
static int
acpi_processor_get_performance (
struct acpi_processor *pr)
static int
acpi_processor_get_platform_limit (
struct acpi_processor* pr)
{
ACPI_FUNCTION_TRACE("acpi_processor_get_performance_state");
acpi_status status = 0;
unsigned long ppc = 0;
ACPI_FUNCTION_TRACE("acpi_processor_get_platform_limit");
if (!pr)
return_VALUE(-EINVAL);
if (!pr->flags.performance)
return_VALUE(0);
/*
* _PPC indicates the maximum state currently supported by the platform
* (e.g. 0 = states 0..n; 1 = states 1..n; etc.
*/
status = acpi_evaluate_integer(pr->handle, "_PPC", NULL, &ppc);
if(ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PPC\n"));
return_VALUE(-ENODEV);
}
/* TBD */
pr->performance.platform_limit = (int) ppc;
return_VALUE(0);
}
static int
acpi_processor_get_performance_control (
struct acpi_processor *pr)
{
int result = 0;
acpi_status status = 0;
acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
acpi_object *pct = NULL;
acpi_object obj = {0};
struct acpi_pct_register *reg = NULL;
ACPI_FUNCTION_TRACE("acpi_processor_get_performance_control");
status = acpi_evaluate_object(pr->handle, "_PCT", NULL, &buffer);
if(ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PCT\n"));
return_VALUE(-ENODEV);
}
pct = (acpi_object *) buffer.pointer;
if (!pct || (pct->type != ACPI_TYPE_PACKAGE)
|| (pct->package.count != 2)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PCT data\n"));
result = -EFAULT;
goto end;
}
/*
* control_register
*/
obj = pct->package.elements[0];
if ((obj.type != ACPI_TYPE_BUFFER)
|| (obj.buffer.length < sizeof(struct acpi_pct_register))
|| (obj.buffer.pointer == NULL)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Invalid _PCT data (control_register)\n"));
result = -EFAULT;
goto end;
}
reg = (struct acpi_pct_register *) (obj.buffer.pointer);
if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Unsupported address space [%d] (control_register)\n",
(u32) reg->space_id));
result = -EFAULT;
goto end;
}
pr->performance.control_register = (u16) reg->address;
/*
* status_register
*/
obj = pct->package.elements[1];
if ((obj.type != ACPI_TYPE_BUFFER)
|| (obj.buffer.length < sizeof(struct acpi_pct_register))
|| (obj.buffer.pointer == NULL)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Invalid _PCT data (status_register)\n"));
result = -EFAULT;
goto end;
}
reg = (struct acpi_pct_register *) (obj.buffer.pointer);
if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Unsupported address space [%d] (status_register)\n",
(u32) reg->space_id));
result = -EFAULT;
goto end;
}
pr->performance.status_register = (u16) reg->address;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"control_register[0x%04x] status_register[0x%04x]\n",
pr->performance.control_register,
pr->performance.status_register));
end:
kfree(buffer.pointer);
return_VALUE(result);
}
static int
acpi_processor_get_performance_states (
struct acpi_processor* pr)
{
int result = 0;
acpi_status status = AE_OK;
acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
acpi_buffer format = {sizeof("NNNNNN"), "NNNNNN"};
acpi_buffer state = {0, NULL};
acpi_object *pss = NULL;
int i = 0;
ACPI_FUNCTION_TRACE("acpi_processor_get_performance_states");
status = acpi_evaluate_object(pr->handle, "_PSS", NULL, &buffer);
if(ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Error evaluating _PSS\n"));
return_VALUE(-ENODEV);
}
pss = (acpi_object *) buffer.pointer;
if (!pss || (pss->type != ACPI_TYPE_PACKAGE)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSS data\n"));
result = -EFAULT;
goto end;
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d performance states\n",
pss->package.count));
if (pss->package.count > ACPI_PROCESSOR_MAX_PERFORMANCE) {
pr->performance.state_count = ACPI_PROCESSOR_MAX_PERFORMANCE;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Limiting number of states to max (%d)\n",
ACPI_PROCESSOR_MAX_PERFORMANCE));
}
else
pr->performance.state_count = pss->package.count;
if (pr->performance.state_count > 1)
pr->flags.performance = 1;
for (i = 0; i < pr->performance.state_count; i++) {
struct acpi_processor_px *px = &(pr->performance.states[i]);
state.length = sizeof(struct acpi_processor_px);
state.pointer = px;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Extracting state %d\n", i));
status = acpi_extract_package(&(pss->package.elements[i]),
&format, &state);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid _PSS data\n"));
result = -EFAULT;
goto end;
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"State [%d]: core_frequency[%d] power[%d] transition_latency[%d] bus_master_latency[%d] control[0x%x] status[0x%x]\n",
i,
(u32) px->core_frequency,
(u32) px->power,
(u32) px->transition_latency,
(u32) px->bus_master_latency,
(u32) px->control,
(u32) px->status));
}
end:
kfree(buffer.pointer);
return_VALUE(result);
}
static int
acpi_processor_set_performance (
struct acpi_processor *pr,
int state)
{
ACPI_FUNCTION_TRACE("acpi_processor_set_performance_state");
u16 port = 0;
u8 value = 0;
int i = 0;
ACPI_FUNCTION_TRACE("acpi_processor_set_performance");
if (!pr)
return_VALUE(-EINVAL);
......@@ -721,13 +1004,71 @@ acpi_processor_set_performance (
if (!pr->flags.performance)
return_VALUE(-ENODEV);
if (state >= pr->performance.state_count)
if (state >= pr->performance.state_count) {
ACPI_DEBUG_PRINT((ACPI_DB_WARN,
"Invalid target state (P%d)\n", state));
return_VALUE(-ENODEV);
}
if (state < pr->performance.platform_limit) {
ACPI_DEBUG_PRINT((ACPI_DB_WARN,
"Platform limit (P%d) overrides target state (P%d)\n",
pr->performance.platform_limit, state));
return_VALUE(-ENODEV);
}
if (state == pr->performance.state)
if (state == pr->performance.state) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Already at target state (P%d)\n", state));
return_VALUE(0);
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Transitioning from P%d to P%d\n",
pr->performance.state, state));
/*
* First we write the target state's 'control' value to the
* control_register.
*/
port = pr->performance.control_register;
value = (u16) pr->performance.states[state].control;
/* TBD */
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Writing 0x%02x to port 0x%04x\n", value, port));
outb(value, port);
/*
* Then we read the 'status_register' and compare the value with the
* target state's 'status' to make sure the transition was successful.
* Note that we'll poll for up to 1ms (100 cycles of 10us) before
* giving up.
*/
port = pr->performance.status_register;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Looking for 0x%02x from port 0x%04x\n",
(u8) pr->performance.states[state].status, port));
for (i=0; i<100; i++) {
value = inb(port);
if (value == (u8) pr->performance.states[state].status)
break;
udelay(10);
}
if (value != pr->performance.states[state].status) {
ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Transition failed\n"));
return_VALUE(-ENODEV);
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Transition successful after %d microseconds\n",
i * 10));
pr->performance.state = state;
return_VALUE(0);
}
......@@ -738,13 +1079,37 @@ acpi_processor_get_performance_info (
struct acpi_processor *pr)
{
int result = 0;
acpi_status status = AE_OK;
acpi_handle handle = NULL;
ACPI_FUNCTION_TRACE("acpi_processor_get_performance_info");
if (!pr)
return_VALUE(-EINVAL);
/* TBD: Support ACPI 2.0 objects */
status = acpi_get_handle(pr->handle, "_PCT", &handle);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"ACPI-based processor performance control unavailable\n"));
return_VALUE(0);
}
result = acpi_processor_get_performance_control(pr);
if (0 != result)
return_VALUE(result);
result = acpi_processor_get_performance_states(pr);
if (0 != result)
return_VALUE(result);
result = acpi_processor_get_platform_limit(pr);
if (0 != result)
return_VALUE(result);
/*
* TBD: Don't trust the latency values we get from BIOS, but rather
* measure the latencies during run-time (e.g. get_latencies).
*/
return_VALUE(0);
}
......@@ -776,32 +1141,29 @@ acpi_processor_get_throttling (
__cli();
duty_mask = pr->throttling.state_count - 1;
duty_mask <<= pr->throttling.duty_offset;
value = inb(pr->throttling.address);
value = inl(pr->throttling.address);
/*
* Compute the current throttling state when throttling is enabled
* (bit 4 is on). Note that the reverse_throttling flag indicates
* that the duty_value is opposite of that specified by ACPI.
* (bit 4 is on).
*/
if (value & 0x10) {
duty_value = value & duty_mask;
duty_value >>= pr->throttling.duty_offset;
if (duty_value) {
if (pr->errata.piix4.reverse_throttle)
state = duty_value;
else
state = pr->throttling.state_count-duty_value;
}
if (duty_value)
state = pr->throttling.state_count-duty_value;
}
pr->throttling.state = state;
__sti();
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Throttling state is T%d (%d%% throttling applied)\n",
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Throttling state is T%d (%d%% throttling applied)\n",
state, pr->throttling.states[state].performance));
return_VALUE(0);
......@@ -825,7 +1187,7 @@ acpi_processor_set_throttling (
if ((state < 0) || (state > (pr->throttling.state_count - 1)))
return_VALUE(-EINVAL);
if (!pr->flags.throttling || !pr->throttling.states[state].valid)
if (!pr->flags.throttling)
return_VALUE(-ENODEV);
if (state == pr->throttling.state)
......@@ -834,20 +1196,16 @@ acpi_processor_set_throttling (
__cli();
/*
* Calculate the duty_value and duty_mask. Note that the
* reverse_throttling flag indicates that the duty_value is
* opposite of that specified by ACPI.
* Calculate the duty_value and duty_mask.
*/
if (state) {
if (pr->errata.piix4.reverse_throttle)
duty_value = state;
else
duty_value = pr->throttling.state_count - state;
duty_value = pr->throttling.state_count - state;
duty_value <<= pr->throttling.duty_offset;
/* Used to clear all duty_value bits */
duty_mask = pr->performance.state_count - 1;
duty_mask = pr->throttling.state_count - 1;
duty_mask <<= acpi_fadt.duty_offset;
duty_mask = ~duty_mask;
}
......@@ -856,7 +1214,7 @@ acpi_processor_set_throttling (
* Disable throttling by writing a 0 to bit 4. Note that we must
* turn it off before you can change the duty_value.
*/
value = inb(pr->throttling.address);
value = inl(pr->throttling.address);
if (value & 0x10) {
value &= 0xFFFFFFEF;
outl(value, pr->throttling.address);
......@@ -879,8 +1237,9 @@ acpi_processor_set_throttling (
__sti();
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Throttling state set to T%d (%d%%)\n",
state, (pr->throttling.states[state].performance?pr->throttling.states[state].performance/10:0)));
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Throttling state set to T%d (%d%%)\n", state,
(pr->throttling.states[state].performance?pr->throttling.states[state].performance/10:0)));
return_VALUE(0);
}
......@@ -912,13 +1271,24 @@ acpi_processor_get_throttling_info (
return_VALUE(0);
}
else if (!pr->throttling.duty_width) {
ACPI_DEBUG_PRINT((ACPI_DB_WARN, "Invalid duty_width\n"));
return_VALUE(-EFAULT);
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No throttling states\n"));
return_VALUE(0);
}
/* TBD: Support duty_cycle values that span bit 4. */
else if ((pr->throttling.duty_offset
+ pr->throttling.duty_width) > 4) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "duty_cycle spans bit 4\n"));
ACPI_DEBUG_PRINT((ACPI_DB_WARN, "duty_cycle spans bit 4\n"));
return_VALUE(0);
}
/*
* PIIX4 Errata: We don't support throttling on the original PIIX4.
* This shouldn't be an issue as few (if any) mobile systems ever
* used this part.
*/
if (errata.piix4.throttle) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Throttling not supported on PIIX4 A- or B-step\n"));
return_VALUE(0);
}
......@@ -935,7 +1305,6 @@ acpi_processor_get_throttling_info (
for (i=0; i<pr->throttling.state_count; i++) {
pr->throttling.states[i].performance = step * i;
pr->throttling.states[i].power = step * i;
pr->throttling.states[i].valid = 1;
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d throttling states\n",
......@@ -973,19 +1342,76 @@ acpi_processor_get_throttling_info (
Limit Interface
-------------------------------------------------------------------------- */
static int
acpi_processor_apply_limit (
struct acpi_processor* pr)
{
int result = 0;
u16 px = 0;
u16 tx = 0;
ACPI_FUNCTION_TRACE("acpi_processor_apply_limit");
if (!pr)
return_VALUE(-EINVAL);
if (!pr->flags.limit)
return_VALUE(-ENODEV);
if (pr->flags.performance) {
px = pr->performance.platform_limit;
if (pr->limit.user.px > px)
px = pr->limit.user.px;
if (pr->limit.thermal.px > px)
px = pr->limit.thermal.px;
result = acpi_processor_set_performance(pr, px);
if (0 != result)
goto end;
}
if (pr->flags.throttling) {
if (pr->limit.user.tx > tx)
tx = pr->limit.user.tx;
if (pr->limit.thermal.tx > tx)
tx = pr->limit.thermal.tx;
result = acpi_processor_set_throttling(pr, tx);
if (0 != result)
goto end;
}
pr->limit.state.px = px;
pr->limit.state.tx = tx;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d] limit set to (P%d:T%d)\n",
pr->id,
pr->limit.state.px,
pr->limit.state.tx));
end:
if (0 != result)
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to set limit\n"));
return_VALUE(result);
}
int
acpi_processor_set_limit (
acpi_processor_set_thermal_limit (
acpi_handle handle,
int type,
int *state)
int type)
{
int result = 0;
struct acpi_processor *pr = NULL;
struct acpi_device *device = NULL;
int px = 0;
int tx = 0;
ACPI_FUNCTION_TRACE("acpi_processor_set_limit");
ACPI_FUNCTION_TRACE("acpi_processor_set_thermal_limit");
if (!state)
if ((type < ACPI_PROCESSOR_LIMIT_NONE)
|| (type > ACPI_PROCESSOR_LIMIT_DECREMENT))
return_VALUE(-EINVAL);
result = acpi_bus_get_device(handle, &device);
......@@ -999,56 +1425,75 @@ acpi_processor_set_limit (
if (!pr->flags.limit)
return_VALUE(-ENODEV);
/* Thermal limits are always relative to the current Px/Tx state. */
if (pr->flags.performance)
pr->limit.thermal.px = pr->performance.state;
if (pr->flags.throttling)
pr->limit.thermal.tx = pr->throttling.state;
/*
* Our default policy is to only use throttling at the lowest
* performance state.
*/
switch (type) {
case ACPI_PROCESSOR_LIMIT_NONE:
*state = 0;
pr->limit.state = 0;
px = 0;
tx = 0;
break;
case ACPI_PROCESSOR_LIMIT_INCREMENT:
if (*state == (pr->limit.state_count - 1)) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Already at maximum limit state\n"));
return_VALUE(1);
if (pr->flags.performance) {
if (px == (pr->performance.state_count - 1))
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"At maximum performance state\n"));
else {
px++;
goto end;
}
}
if (pr->flags.throttling) {
if (tx == (pr->throttling.state_count - 1))
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"At maximum throttling state\n"));
else
tx++;
}
*state = ++pr->limit.state;
break;
case ACPI_PROCESSOR_LIMIT_DECREMENT:
if (*state == 0) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Already at minimum limit state\n"));
return_VALUE(1);
if (pr->flags.performance) {
if (px == pr->performance.platform_limit)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"At minimum performance state\n"));
else {
px--;
goto end;
}
}
if (pr->flags.throttling) {
if (tx == 0)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"At minimum throttling state\n"));
else
tx--;
}
*state = --pr->limit.state;
break;
default:
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid limit type [%d]\n",
type));
*state = pr->limit.state;
return_VALUE(-EINVAL);
break;
}
if (pr->flags.performance) {
result = acpi_processor_set_performance(pr,
pr->limit.states[*state].px);
if (0 != result)
goto end;
}
if (pr->flags.throttling) {
result = acpi_processor_set_throttling(pr,
pr->limit.states[*state].tx);
if (0 != result)
goto end;
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Processor [%d] limit now %d%% (P%d:T%d)\n",
pr->id,
pr->limit.states[*state].performance / 10,
pr->limit.states[*state].px,
pr->limit.states[*state].tx));
end:
pr->limit.thermal.px = px;
pr->limit.thermal.tx = tx;
result = acpi_processor_apply_limit(pr);
if (0 != result)
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Unable to set limit\n"));
ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Unable to set thermal limit\n"));
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Thermal limit now (P%d:T%d)\n",
pr->limit.thermal.px,
pr->limit.thermal.tx));
return_VALUE(result);
}
......@@ -1058,58 +1503,12 @@ static int
acpi_processor_get_limit_info (
struct acpi_processor *pr)
{
int i = 0;
int px = 0;
int tx = 0;
int base_perf = 1000;
int throttle = 0;
ACPI_FUNCTION_TRACE("acpi_processor_get_limit_info");
if (!pr)
return_VALUE(-EINVAL);
/*
* Limit
* -----
* Our default policy is to only use throttling at the lowest
* performance state. This is enforced by adding throttling states
* after perormance states. We also only expose throttling states
* less than the maximum throttle value (e.g. 50%).
*/
if (pr->flags.performance) {
for (px=0; px<pr->performance.state_count; px++) {
if (!pr->performance.states[px].valid)
continue;
i = pr->limit.state_count++;
pr->limit.states[i].px = px;
pr->limit.states[i].performance = (pr->performance.states[px].core_frequency / pr->performance.states[0].core_frequency) * 1000;
pr->limit.states[i].valid = 1;
}
px--;
base_perf = pr->limit.states[i].performance;
}
if (pr->flags.throttling) {
for (tx=0; tx<pr->throttling.state_count; tx++) {
if (!pr->throttling.states[tx].valid)
continue;
if (pr->throttling.states[tx].performance > ACPI_PROCESSOR_MAX_THROTTLE)
continue;
i = pr->limit.state_count++;
pr->limit.states[i].px = px;
pr->limit.states[i].tx = tx;
throttle = (base_perf * pr->throttling.states[tx].performance) / 1000;
pr->limit.states[i].performance = base_perf - throttle;
pr->limit.states[i].valid = 1;
}
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d limit states\n",
pr->limit.state_count));
if (pr->limit.state_count)
if (pr->flags.performance || pr->flags.throttling)
pr->flags.limit = 1;
return_VALUE(0);
......@@ -1278,11 +1677,11 @@ acpi_processor_read_performance (
p += sprintf(p, "states:\n");
for (i=0; i<pr->performance.state_count; i++)
p += sprintf(p, " %cP%d: %d Mhz, %d mW %s\n",
p += sprintf(p, " %cP%d: %d Mhz, %d mW, %d uS\n",
(i == pr->performance.state?'*':' '), i,
pr->performance.states[i].core_frequency,
pr->performance.states[i].power,
(pr->performance.states[i].valid?"":"(disabled)"));
(u32) pr->performance.states[i].core_frequency,
(u32) pr->performance.states[i].power,
(u32) pr->performance.states[i].transition_latency);
end:
len = (p - page);
......@@ -1316,8 +1715,8 @@ acpi_processor_write_performance (
return_VALUE(-EFAULT);
state_string[count] = '\0';
result = acpi_processor_set_throttling(pr,
result = acpi_processor_set_performance(pr,
simple_strtoul(state_string, NULL, 0));
if (0 != result)
return_VALUE(result);
......@@ -1339,6 +1738,7 @@ acpi_processor_read_throttling (
char *p = page;
int len = 0;
int i = 0;
int result = 0;
ACPI_FUNCTION_TRACE("acpi_processor_read_throttling");
......@@ -1350,6 +1750,13 @@ acpi_processor_read_throttling (
goto end;
}
result = acpi_processor_get_throttling(pr);
if (result) {
p += sprintf(p, "Could not determine current throttling state.\n");
goto end;
}
p += sprintf(p, "state count: %d\n",
pr->throttling.state_count);
......@@ -1359,10 +1766,9 @@ acpi_processor_read_throttling (
p += sprintf(p, "states:\n");
for (i=0; i<pr->throttling.state_count; i++)
p += sprintf(p, " %cT%d: %02d%% %s\n",
p += sprintf(p, " %cT%d: %02d%%\n",
(i == pr->throttling.state?'*':' '), i,
(pr->throttling.states[i].performance?pr->throttling.states[i].performance/10:0),
(pr->throttling.states[i].valid?"":"(disabled)"));
(pr->throttling.states[i].performance?pr->throttling.states[i].performance/10:0));
end:
len = (p - page);
......@@ -1418,7 +1824,6 @@ acpi_processor_read_limit (
struct acpi_processor *pr = (struct acpi_processor *) data;
char *p = page;
int len = 0;
int i = 0;
ACPI_FUNCTION_TRACE("acpi_processor_read_limit");
......@@ -1430,22 +1835,17 @@ acpi_processor_read_limit (
goto end;
}
p += sprintf(p, "state count: %d\n",
pr->limit.state_count);
p += sprintf(p, "active limit: P%d:T%d\n",
pr->limit.state.px, pr->limit.state.tx);
p += sprintf(p, "active state: L%d\n",
pr->limit.state);
p += sprintf(p, "platform limit: P%d:T0\n",
pr->flags.performance?pr->performance.platform_limit:0);
p += sprintf(p, "states:\n");
p += sprintf(p, "user limit: P%d:T%d\n",
pr->limit.user.px, pr->limit.user.tx);
for (i=0; i<pr->limit.state_count; i++)
p += sprintf(p, " %cL%d: %02d%% [P%d:T%d] %s\n",
(i == pr->limit.state?'*':' '),
i,
pr->limit.states[i].performance / 10,
pr->limit.states[i].px,
pr->limit.states[i].tx,
pr->limit.states[i].valid?"":"(disabled)");
p += sprintf(p, "thermal limit: P%d:T%d\n",
pr->limit.thermal.px, pr->limit.thermal.tx);
end:
len = (p - page);
......@@ -1468,25 +1868,47 @@ acpi_processor_write_limit (
{
int result = 0;
struct acpi_processor *pr = (struct acpi_processor *) data;
char limit_string[12] = {'\0'};
int limit = 0;
int state = 0;
char limit_string[25] = {'\0'};
int px = 0;
int tx = 0;
ACPI_FUNCTION_TRACE("acpi_processor_write_limit");
if (!pr || (count > sizeof(limit_string) - 1))
if (!pr || (count > sizeof(limit_string) - 1)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid argument\n"));
return_VALUE(-EINVAL);
}
if (copy_from_user(limit_string, buffer, count))
if (copy_from_user(limit_string, buffer, count)) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data\n"));
return_VALUE(-EFAULT);
}
limit_string[count] = '\0';
limit = simple_strtoul(limit_string, NULL, 0);
result = acpi_processor_set_limit(pr->handle, limit, &state);
if (0 != result)
return_VALUE(result);
if (sscanf(limit_string, "%d:%d", &px, &tx) != 2) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid data format\n"));
return_VALUE(-EINVAL);
}
if (pr->flags.performance) {
if ((px < pr->performance.platform_limit)
|| (px > (pr->performance.state_count - 1))) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid px\n"));
return_VALUE(-EINVAL);
}
pr->limit.user.px = px;
}
if (pr->flags.throttling) {
if ((tx < 0) || (tx > (pr->throttling.state_count - 1))) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Invalid tx\n"));
return_VALUE(-EINVAL);
}
pr->limit.user.tx = tx;
}
result = acpi_processor_apply_limit(pr);
return_VALUE(count);
}
......@@ -1564,7 +1986,7 @@ acpi_processor_add_fs (
entry->data = acpi_driver_data(device);
}
/* 'thermal_limit' [R/W] */
/* 'limit' [R/W] */
entry = create_proc_entry(ACPI_PROCESSOR_FILE_LIMIT,
S_IFREG|S_IRUGO|S_IWUSR, acpi_device_dir(device));
if (!entry)
......@@ -1617,10 +2039,10 @@ acpi_processor_get_info (
#ifdef CONFIG_SMP
if (smp_num_cpus > 1)
acpi_processor_smp = smp_num_cpus;
errata.smp = smp_num_cpus;
#endif
acpi_processor_get_errata(pr);
acpi_processor_errata(pr);
/*
* Check to see if we have bus mastering arbitration control. This
......@@ -1687,6 +2109,7 @@ acpi_processor_notify (
u32 event,
void *data)
{
int result = 0;
struct acpi_processor *pr = (struct acpi_processor *) data;
struct acpi_device *device = NULL;
......@@ -1700,7 +2123,15 @@ acpi_processor_notify (
switch (event) {
case ACPI_PROCESSOR_NOTIFY_PERFORMANCE:
result = acpi_processor_get_platform_limit(pr);
if (0 == result)
acpi_processor_apply_limit(pr);
acpi_bus_generate_event(device, event,
pr->performance.platform_limit);
break;
case ACPI_PROCESSOR_NOTIFY_POWER:
/* TBD */
acpi_bus_generate_event(device, event, 0);
break;
default:
......@@ -1745,9 +2176,6 @@ acpi_processor_add (
if (0 != result)
goto end;
/*
* TBD: Fix notify handler installation for processors.
*
status = acpi_install_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,
acpi_processor_notify, pr);
if (ACPI_FAILURE(status)) {
......@@ -1756,16 +2184,13 @@ acpi_processor_add (
result = -ENODEV;
goto end;
}
*/
acpi_processor_list[pr->id] = pr;
processors[pr->id] = pr;
/*
* Set Idle Handler
* ----------------
* Install the idle handler if power management (states other than C1)
* is supported. Note that the default idle handler (default_idle)
* will be used on platforms that only support C1.
* Install the idle handler if processor power management is supported.
* Note that the default idle handler (default_idle) will be used on
* platforms that only support C1.
*/
if ((pr->id == 0) && (pr->flags.power)) {
pm_idle_save = pm_idle;
......@@ -1781,8 +2206,6 @@ acpi_processor_add (
printk(", %d performance states", pr->performance.state_count);
if (pr->flags.throttling)
printk(", %d throttling states", pr->throttling.state_count);
if (pr->errata.piix4.bmisx)
printk(", PIIX4 errata");
printk(")\n");
end:
......@@ -1810,7 +2233,10 @@ acpi_processor_remove (
pr = (struct acpi_processor *) acpi_driver_data(device);
/*
/* Unregister the idle handler when processor #0 is removed. */
if (pr->id == 0)
pm_idle = pm_idle_save;
status = acpi_remove_notify_handler(pr->handle, ACPI_DEVICE_NOTIFY,
acpi_processor_notify);
if (ACPI_FAILURE(status)) {
......@@ -1818,15 +2244,10 @@ acpi_processor_remove (
"Error removing notify handler\n"));
return_VALUE(-ENODEV);
}
*/
/* Unregister the idle handler when processor #0 is removed. */
if (pr->id == 0)
pm_idle = pm_idle_save;
acpi_processor_remove_fs(device);
acpi_processor_list[pr->id] = NULL;
processors[pr->id] = NULL;
kfree(pr);
......@@ -1841,7 +2262,8 @@ acpi_processor_init (void)
ACPI_FUNCTION_TRACE("acpi_processor_init");
memset(&acpi_processor_list, 0, sizeof(acpi_processor_list));
memset(&processors, 0, sizeof(processors));
memset(&errata, 0, sizeof(errata));
result = acpi_bus_register_driver(&acpi_processor_driver);
if (0 > result)
......
/*
* acpi_system.c - ACPI System Driver ($Revision: 40 $)
* acpi_system.c - ACPI System Driver ($Revision: 45 $)
*
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
......@@ -31,6 +31,7 @@
#include <linux/spinlock.h>
#include <linux/poll.h>
#include <linux/delay.h>
#include <linux/sysrq.h>
#include <linux/pm.h>
#include <asm/uaccess.h>
#include <asm/acpi.h>
......@@ -86,9 +87,8 @@ static void
acpi_power_off (void)
{
acpi_enter_sleep_state_prep(ACPI_STATE_S5);
acpi_disable_irqs();
ACPI_DISABLE_IRQS();
acpi_enter_sleep_state(ACPI_STATE_S5);
acpi_disable_irqs();
}
#endif /*CONFIG_PM*/
......@@ -123,7 +123,7 @@ acpi_system_restore_state (
device_resume(RESUME_POWER_ON);
/* enable interrupts once again */
acpi_enable_irqs();
ACPI_ENABLE_IRQS();
/* restore device context */
device_resume(RESUME_RESTORE_STATE);
......@@ -200,7 +200,7 @@ acpi_system_save_state(
* But, we want it done early, so we don't get any suprises during
* the device suspend sequence.
*/
acpi_disable_irqs();
ACPI_DISABLE_IRQS();
/* Unconditionally turn off devices.
* Obvious if we enter a sleep state.
......@@ -304,7 +304,7 @@ acpi_suspend (
return status;
/* disable interrupts and flush caches */
acpi_disable_irqs();
ACPI_DISABLE_IRQS();
wbinvd();
/* perform OS-specific sleep actions */
......@@ -318,7 +318,7 @@ acpi_suspend (
acpi_leave_sleep_state(state);
/* make sure interrupts are enabled */
acpi_enable_irqs();
ACPI_ENABLE_IRQS();
/* reset firmware waking vector */
acpi_set_firmware_waking_vector((ACPI_PHYSICAL_ADDRESS) 0);
......@@ -570,7 +570,6 @@ acpi_system_read_debug (
{
char *p = page;
int size = 0;
u32 var;
if (off != 0)
goto end;
......@@ -607,7 +606,6 @@ acpi_system_write_debug (
void *data)
{
char debug_string[12] = {'\0'};
u32 *pvar;
ACPI_FUNCTION_TRACE("acpi_system_write_debug");
......@@ -1126,6 +1124,23 @@ acpi_system_remove_fs (
Driver Interface
-------------------------------------------------------------------------- */
#if defined(CONFIG_MAGIC_SYSRQ) && defined(CONFIG_PM)
/* Simple wrapper calling power down function. */
static void acpi_sysrq_power_off(int key, struct pt_regs *pt_regs,
struct kbd_struct *kbd, struct tty_struct *tty)
{
acpi_power_off();
}
struct sysrq_key_op sysrq_acpi_poweroff_op = {
handler: &acpi_sysrq_power_off,
help_msg: "Off",
action_msg: "Power Off\n"
};
#endif /* CONFIG_MAGIC_SYSRQ */
static int
acpi_system_add (
struct acpi_device *device)
......@@ -1168,8 +1183,10 @@ acpi_system_add (
#ifdef CONFIG_PM
/* Install the soft-off (S5) handler. */
if (system->states[ACPI_STATE_S5])
if (system->states[ACPI_STATE_S5]) {
pm_power_off = acpi_power_off;
register_sysrq_key('o', &sysrq_acpi_poweroff_op);
}
#endif
end:
......@@ -1196,8 +1213,10 @@ acpi_system_remove (
#ifdef CONFIG_PM
/* Remove the soft-off (S5) handler. */
if (system->states[ACPI_STATE_S5])
if (system->states[ACPI_STATE_S5]) {
unregister_sysrq_key('o', &sysrq_acpi_poweroff_op);
pm_power_off = NULL;
}
#endif
acpi_system_remove_fs(device);
......
/*
* acpi_thermal.c - ACPI Thermal Zone Driver ($Revision: 33 $)
* acpi_thermal.c - ACPI Thermal Zone Driver ($Revision: 36 $)
*
* Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
* Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
......@@ -78,7 +78,6 @@ struct acpi_thermal_state {
u8 passive:1;
u8 active:1;
u8 reserved:4;
int passive_index; /* a.k.a. limit state */
int active_index;
};
......@@ -467,15 +466,23 @@ acpi_thermal_passive (
*/
if (tz->temperature >= passive->temperature) {
trend = (passive->tc1 * (tz->temperature - tz->last_temperature)) + (passive->tc2 * (tz->temperature - passive->temperature));
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "trend[%d]=(tc1[%lu]*(tmp[%lu]-last[%lu]))+(tc2[%lu]*(tmp[%lu]-psv[%lu]))\n", trend, passive->tc1, tz->temperature, tz->last_temperature, passive->tc2, tz->temperature, passive->temperature));
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"trend[%d]=(tc1[%lu]*(tmp[%lu]-last[%lu]))+(tc2[%lu]*(tmp[%lu]-psv[%lu]))\n",
trend, passive->tc1, tz->temperature,
tz->last_temperature, passive->tc2,
tz->temperature, passive->temperature));
/* Heating up? */
if (trend > 0)
for (i=0; i<passive->devices.count; i++)
acpi_processor_set_limit(passive->devices.handles[i], ACPI_PROCESSOR_LIMIT_INCREMENT, &tz->state.passive_index);
acpi_processor_set_thermal_limit(
passive->devices.handles[i],
ACPI_PROCESSOR_LIMIT_INCREMENT);
/* Cooling off? */
else if (trend < 0)
for (i=0; i<passive->devices.count; i++)
acpi_processor_set_limit(passive->devices.handles[i], ACPI_PROCESSOR_LIMIT_DECREMENT, &tz->state.passive_index);
acpi_processor_set_thermal_limit(
passive->devices.handles[i],
ACPI_PROCESSOR_LIMIT_DECREMENT);
}
/*
......@@ -487,10 +494,13 @@ acpi_thermal_passive (
*/
else if (tz->trips.passive.flags.enabled) {
for (i=0; i<passive->devices.count; i++)
acpi_processor_set_limit(passive->devices.handles[i], ACPI_PROCESSOR_LIMIT_DECREMENT, &tz->state.passive_index);
if (0 == tz->state.passive_index) {
result = acpi_processor_set_thermal_limit(
passive->devices.handles[i],
ACPI_PROCESSOR_LIMIT_DECREMENT);
if (1 == result) {
tz->trips.passive.flags.enabled = 0;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Disabling passive cooling (zone is cool)\n"));
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Disabling passive cooling (zone is cool)\n"));
}
}
......@@ -671,7 +681,7 @@ acpi_thermal_check (
if (timer_pending(&(tz->timer)))
mod_timer(&(tz->timer), (HZ * sleep_time) / 1000);
else {
tz->timer.data = (u32) tz;
tz->timer.data = (unsigned long) tz;
tz->timer.function = acpi_thermal_run;
tz->timer.expires = jiffies + (HZ * sleep_time) / 1000;
add_timer(&(tz->timer));
......@@ -720,7 +730,7 @@ acpi_thermal_read_state (
if (tz->state.hot)
p += sprintf(p, "hot ");
if (tz->state.passive)
p += sprintf(p, "passive[%d] ", tz->state.passive_index);
p += sprintf(p, "passive ");
if (tz->state.active)
p += sprintf(p, "active[%d]", tz->state.active_index);
p += sprintf(p, "\n");
......@@ -810,9 +820,10 @@ acpi_thermal_read_trip_points (
tz->trips.passive.tc1,
tz->trips.passive.tc2,
tz->trips.passive.tsp);
for (j=0; j<tz->trips.passive.devices.count; j++)
p += sprintf(p, "0x%p ",
tz->trips.passive.devices.handles[j]);
for (j=0; j<tz->trips.passive.devices.count; j++) {
p += sprintf(p, "0x%p ", tz->trips.passive.devices.handles[j]);
}
p += sprintf(p, "\n");
}
......
/******************************************************************************
*
* Name: acenv.h - Generation environment specific items
* $Revision: 85 $
* $Revision: 86 $
*
*****************************************************************************/
......@@ -284,11 +284,9 @@ typedef char *va_list;
#define ACPI_INTERNAL_VAR_XFACE
#define ACPI_ASM_MACROS
#define causeinterrupt(level)
#define BREAKPOINT3
#define acpi_disable_irqs()
#define acpi_enable_irqs()
#define halt()
#define ACPI_DISABLE_IRQS()
#define ACPI_ENABLE_IRQS()
#define ACPI_ACQUIRE_GLOBAL_LOCK(Glptr, acq)
#define ACPI_RELEASE_GLOBAL_LOCK(Glptr, acq)
......@@ -299,9 +297,7 @@ typedef char *va_list;
/* Don't want software interrupts within a ring3 application */
#undef causeinterrupt
#undef BREAKPOINT3
#define causeinterrupt(level)
#define BREAKPOINT3
#endif
......
/******************************************************************************
*
* Name: acgcc.h - GCC specific defines, etc.
* $Revision: 19 $
* $Revision: 22 $
*
*****************************************************************************/
......@@ -30,7 +30,8 @@
#ifdef __ia64__
#define _IA64
#define COMPILER_DEPENDENT_UINT64 unsigned long
#define COMPILER_DEPENDENT_INT64 long
#define COMPILER_DEPENDENT_UINT64 unsigned long
/*
* Calling conventions:
......@@ -52,10 +53,9 @@
/* Asm macros */
#define ACPI_ASM_MACROS
#define causeinterrupt(level)
#define BREAKPOINT3
#define acpi_disable_irqs() __cli()
#define acpi_enable_irqs() __sti()
#define ACPI_DISABLE_IRQS() __cli()
#define ACPI_ENABLE_IRQS() __sti()
/*! [Begin] no source code translation */
......@@ -111,7 +111,8 @@
#else /* DO IA32 */
#define COMPILER_DEPENDENT_UINT64 unsigned long long
#define COMPILER_DEPENDENT_INT64 long long
#define COMPILER_DEPENDENT_UINT64 unsigned long long
/*
* Calling conventions:
......@@ -129,11 +130,9 @@
/* Asm macros */
#define ACPI_ASM_MACROS
#define causeinterrupt(level)
#define BREAKPOINT3
#define acpi_disable_irqs() __cli()
#define acpi_enable_irqs() __sti()
#define halt() __asm__ __volatile__ ("sti; hlt":::"memory")
#define ACPI_DISABLE_IRQS() __cli()
#define ACPI_ENABLE_IRQS() __sti()
/*! [Begin] no source code translation
*
......
/******************************************************************************
*
* Name: aclinux.h - OS specific defines, etc.
* $Revision: 15 $
* $Revision: 19 $
*
*****************************************************************************/
......@@ -42,14 +42,20 @@
#define strtoul simple_strtoul
#ifdef _IA64
#define ACPI_FLUSH_CPU_CACHE()
#else
#define ACPI_FLUSH_CPU_CACHE() wbinvd()
#endif
#else /* !__KERNEL__ */
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#endif
#endif /* __KERNEL__ */
/* Linux uses GCC */
......
......@@ -33,9 +33,12 @@
/* Fixmap pages to reserve for ACPI boot-time tables (see fixmap.h) */
#define FIX_ACPI_PAGES 4
extern int acpi_mp_config;
char * __acpi_map_table (unsigned long phys_addr, unsigned long size);
extern int acpi_find_rsdp (unsigned long *phys_addr);
extern int acpi_parse_madt (unsigned long phys_addr, unsigned long size);
extern int acpi_boot_init (char *cmdline);
#endif /*CONFIG_ACPI_BOOT*/
......
......@@ -29,6 +29,12 @@
#define _LINUX
#endif
/*
* YES this is ugly.
* But, moving all of ACPI's private headers to include/acpi isn't the right
* answer either.
* Please just ignore it for now.
*/
#include "../../drivers/acpi/include/acpi.h"
#include <asm/acpi.h>
......@@ -270,7 +276,7 @@ struct acpi_table_slit {
struct acpi_table_header header;
u64 localities;
u8 entry[1]; /* real size = localities^2 */
};
} __attribute__ ((packed));
/* Smart Battery Description Table (SBST) */
......@@ -283,7 +289,6 @@ struct acpi_table_sbst {
/* Embedded Controller Boot Resources Table (ECDT) */
/* TBD: acpi_generic_address
struct acpi_table_ecdt {
struct acpi_table_header header;
acpi_generic_address ec_control;
......@@ -292,7 +297,6 @@ struct acpi_table_ecdt {
u8 gpe_bit;
char *ec_id;
} __attribute__ ((packed));
*/
/* Table Handlers */
......@@ -343,9 +347,9 @@ void acpi_table_print_madt_entry (acpi_table_entry_header *);
#ifdef CONFIG_ACPI_PCI
#define ACPI_PCI_ROUTING_PIC 0
#define ACPI_PCI_ROUTING_IOAPIC 1
#define ACPI_PCI_ROUTING_IOSAPIC 2
#define ACPI_INT_MODEL_PIC 0
#define ACPI_INT_MODEL_IOAPIC 1
#define ACPI_INT_MODEL_IOSAPIC 2
struct acpi_prt_entry {
struct list_head node;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment