X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fpci%2Fpci-acpi.c;h=33317df47699d0a69f18b6970583fb23b246f7f9;hb=a044a1b147a1c967e1a4b797c3e24c395f3d878a;hp=a9b00cc2d8850da7d958b8fbc1e13119894fe06d;hpb=427bf532b5ad6db5addc2bce675d13f874397c0c;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index a9b00cc..33317df 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -11,200 +11,13 @@ #include #include #include +#include #include -#include -#include #include #include #include "pci.h" -static u32 ctrlset_buf[3] = {0, 0, 0}; -static u32 global_ctrlsets = 0; -static u8 OSC_UUID[16] = {0x5B, 0x4D, 0xDB, 0x33, 0xF7, 0x1F, 0x1C, 0x40, 0x96, 0x57, 0x74, 0x41, 0xC0, 0x3D, 0xD7, 0x66}; - -static acpi_status -acpi_query_osc ( - acpi_handle handle, - u32 level, - void *context, - void **retval ) -{ - acpi_status status; - struct acpi_object_list input; - union acpi_object in_params[4]; - struct acpi_buffer output; - union acpi_object out_obj; - u32 osc_dw0; - - /* Setting up output buffer */ - output.length = sizeof(out_obj) + 3*sizeof(u32); - output.pointer = &out_obj; - - /* Setting up input parameters */ - input.count = 4; - input.pointer = in_params; - in_params[0].type = ACPI_TYPE_BUFFER; - in_params[0].buffer.length = 16; - in_params[0].buffer.pointer = OSC_UUID; - in_params[1].type = ACPI_TYPE_INTEGER; - in_params[1].integer.value = 1; - in_params[2].type = ACPI_TYPE_INTEGER; - in_params[2].integer.value = 3; - in_params[3].type = ACPI_TYPE_BUFFER; - in_params[3].buffer.length = 12; - in_params[3].buffer.pointer = (u8 *)context; - - status = acpi_evaluate_object(handle, "_OSC", &input, &output); - if (ACPI_FAILURE (status)) { - printk(KERN_DEBUG - "Evaluate _OSC Set fails. Status = 0x%04x\n", status); - return status; - } - if (out_obj.type != ACPI_TYPE_BUFFER) { - printk(KERN_DEBUG - "Evaluate _OSC returns wrong type\n"); - return AE_TYPE; - } - osc_dw0 = *((u32 *) out_obj.buffer.pointer); - if (osc_dw0) { - if (osc_dw0 & OSC_REQUEST_ERROR) - printk(KERN_DEBUG "_OSC request fails\n"); - if (osc_dw0 & OSC_INVALID_UUID_ERROR) - printk(KERN_DEBUG "_OSC invalid UUID\n"); - if (osc_dw0 & OSC_INVALID_REVISION_ERROR) - printk(KERN_DEBUG "_OSC invalid revision\n"); - if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) { - /* Update Global Control Set */ - global_ctrlsets = *((u32 *)(out_obj.buffer.pointer+8)); - return AE_OK; - } - return AE_ERROR; - } - - /* Update Global Control Set */ - global_ctrlsets = *((u32 *)(out_obj.buffer.pointer + 8)); - return AE_OK; -} - - -static acpi_status -acpi_run_osc ( - acpi_handle handle, - void *context) -{ - acpi_status status; - struct acpi_object_list input; - union acpi_object in_params[4]; - struct acpi_buffer output; - union acpi_object out_obj; - u32 osc_dw0; - - /* Setting up output buffer */ - output.length = sizeof(out_obj) + 3*sizeof(u32); - output.pointer = &out_obj; - - /* Setting up input parameters */ - input.count = 4; - input.pointer = in_params; - in_params[0].type = ACPI_TYPE_BUFFER; - in_params[0].buffer.length = 16; - in_params[0].buffer.pointer = OSC_UUID; - in_params[1].type = ACPI_TYPE_INTEGER; - in_params[1].integer.value = 1; - in_params[2].type = ACPI_TYPE_INTEGER; - in_params[2].integer.value = 3; - in_params[3].type = ACPI_TYPE_BUFFER; - in_params[3].buffer.length = 12; - in_params[3].buffer.pointer = (u8 *)context; - - status = acpi_evaluate_object(handle, "_OSC", &input, &output); - if (ACPI_FAILURE (status)) { - printk(KERN_DEBUG - "Evaluate _OSC Set fails. Status = 0x%04x\n", status); - return status; - } - if (out_obj.type != ACPI_TYPE_BUFFER) { - printk(KERN_DEBUG - "Evaluate _OSC returns wrong type\n"); - return AE_TYPE; - } - osc_dw0 = *((u32 *) out_obj.buffer.pointer); - if (osc_dw0) { - if (osc_dw0 & OSC_REQUEST_ERROR) - printk(KERN_DEBUG "_OSC request fails\n"); - if (osc_dw0 & OSC_INVALID_UUID_ERROR) - printk(KERN_DEBUG "_OSC invalid UUID\n"); - if (osc_dw0 & OSC_INVALID_REVISION_ERROR) - printk(KERN_DEBUG "_OSC invalid revision\n"); - if (osc_dw0 & OSC_CAPABILITIES_MASK_ERROR) { - printk(KERN_DEBUG "_OSC FW not grant req. control\n"); - return AE_SUPPORT; - } - return AE_ERROR; - } - return AE_OK; -} - -/** - * pci_osc_support_set - register OS support to Firmware - * @flags: OS support bits - * - * Update OS support fields and doing a _OSC Query to obtain an update - * from Firmware on supported control bits. - **/ -acpi_status pci_osc_support_set(u32 flags) -{ - u32 temp; - - if (!(flags & OSC_SUPPORT_MASKS)) { - return AE_TYPE; - } - ctrlset_buf[OSC_SUPPORT_TYPE] |= (flags & OSC_SUPPORT_MASKS); - - /* do _OSC query for all possible controls */ - temp = ctrlset_buf[OSC_CONTROL_TYPE]; - ctrlset_buf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; - ctrlset_buf[OSC_CONTROL_TYPE] = OSC_CONTROL_MASKS; - acpi_get_devices ( PCI_ROOT_HID_STRING, - acpi_query_osc, - ctrlset_buf, - NULL ); - ctrlset_buf[OSC_QUERY_TYPE] = !OSC_QUERY_ENABLE; - ctrlset_buf[OSC_CONTROL_TYPE] = temp; - return AE_OK; -} -EXPORT_SYMBOL(pci_osc_support_set); - -/** - * pci_osc_control_set - commit requested control to Firmware - * @flags: driver's requested control bits - * - * Attempt to take control from Firmware on requested control bits. - **/ -acpi_status pci_osc_control_set(acpi_handle handle, u32 flags) -{ - acpi_status status; - u32 ctrlset; - - ctrlset = (flags & OSC_CONTROL_MASKS); - if (!ctrlset) { - return AE_TYPE; - } - if (ctrlset_buf[OSC_SUPPORT_TYPE] && - ((global_ctrlsets & ctrlset) != ctrlset)) { - return AE_SUPPORT; - } - ctrlset_buf[OSC_CONTROL_TYPE] |= ctrlset; - status = acpi_run_osc(handle, ctrlset_buf); - if (ACPI_FAILURE (status)) { - ctrlset_buf[OSC_CONTROL_TYPE] &= ~ctrlset; - } - - return status; -} -EXPORT_SYMBOL(pci_osc_control_set); - /* * _SxD returns the D-state with the highest power * (lowest D-state number) supported in the S-state "x". @@ -226,37 +39,114 @@ EXPORT_SYMBOL(pci_osc_control_set); * choose from highest power _SxD to lowest power _SxW * else // no _PRW at S-state x * choose highest power _SxD or any lower power - * - * currently we simply return _SxD, if present. */ -static int acpi_pci_choose_state(struct pci_dev *pdev, pm_message_t state) +static pci_power_t acpi_pci_choose_state(struct pci_dev *pdev) +{ + int acpi_state; + + acpi_state = acpi_pm_device_sleep_state(&pdev->dev, NULL); + if (acpi_state < 0) + return PCI_POWER_ERROR; + + switch (acpi_state) { + case ACPI_STATE_D0: + return PCI_D0; + case ACPI_STATE_D1: + return PCI_D1; + case ACPI_STATE_D2: + return PCI_D2; + case ACPI_STATE_D3: + return PCI_D3hot; + } + return PCI_POWER_ERROR; +} + +static bool acpi_pci_power_manageable(struct pci_dev *dev) { - /* TBD */ + acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev); - return -ENODEV; + return handle ? acpi_bus_power_manageable(handle) : false; } static int acpi_pci_set_power_state(struct pci_dev *dev, pci_power_t state) { acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev); - static int state_conv[] = { - [0] = 0, - [1] = 1, - [2] = 2, - [3] = 3, - [4] = 3 + acpi_handle tmp; + static const u8 state_conv[] = { + [PCI_D0] = ACPI_STATE_D0, + [PCI_D1] = ACPI_STATE_D1, + [PCI_D2] = ACPI_STATE_D2, + [PCI_D3hot] = ACPI_STATE_D3, + [PCI_D3cold] = ACPI_STATE_D3 }; - int acpi_state = state_conv[(int __force) state]; + int error = -EINVAL; - if (!handle) + /* If the ACPI device has _EJ0, ignore the device */ + if (!handle || ACPI_SUCCESS(acpi_get_handle(handle, "_EJ0", &tmp))) return -ENODEV; - return acpi_bus_set_power(handle, acpi_state); + + switch (state) { + case PCI_D0: + case PCI_D1: + case PCI_D2: + case PCI_D3hot: + case PCI_D3cold: + error = acpi_bus_set_power(handle, state_conv[state]); + } + + if (!error) + dev_printk(KERN_INFO, &dev->dev, + "power state changed by ACPI to D%d\n", state); + + return error; +} + +static bool acpi_pci_can_wakeup(struct pci_dev *dev) +{ + acpi_handle handle = DEVICE_ACPI_HANDLE(&dev->dev); + + return handle ? acpi_bus_can_wakeup(handle) : false; } +static void acpi_pci_propagate_wakeup_enable(struct pci_bus *bus, bool enable) +{ + while (bus->parent) { + struct pci_dev *bridge = bus->self; + int ret; + + ret = acpi_pm_device_sleep_wake(&bridge->dev, enable); + if (!ret || bridge->is_pcie) + return; + bus = bus->parent; + } + + /* We have reached the root bus. */ + if (bus->bridge) + acpi_pm_device_sleep_wake(bus->bridge, enable); +} + +static int acpi_pci_sleep_wake(struct pci_dev *dev, bool enable) +{ + if (acpi_pci_can_wakeup(dev)) + return acpi_pm_device_sleep_wake(&dev->dev, enable); + + if (!dev->is_pcie) + acpi_pci_propagate_wakeup_enable(dev->bus, enable); + + return 0; +} + +static struct pci_platform_pm_ops acpi_pci_platform_pm = { + .is_manageable = acpi_pci_power_manageable, + .set_state = acpi_pci_set_power_state, + .choose_state = acpi_pci_choose_state, + .can_wakeup = acpi_pci_can_wakeup, + .sleep_wake = acpi_pci_sleep_wake, +}; /* ACPI bus type */ -static int pci_acpi_find_device(struct device *dev, acpi_handle *handle) +static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) { struct pci_dev * pci_dev; acpi_integer addr; @@ -270,7 +160,7 @@ static int pci_acpi_find_device(struct device *dev, acpi_handle *handle) return 0; } -static int pci_acpi_find_root_bridge(struct device *dev, acpi_handle *handle) +static int acpi_pci_find_root_bridge(struct device *dev, acpi_handle *handle) { int num; unsigned int seg, bus; @@ -279,7 +169,7 @@ static int pci_acpi_find_root_bridge(struct device *dev, acpi_handle *handle) * The string should be the same as root bridge's name * Please look at 'pci_scan_bus_parented' */ - num = sscanf(dev->bus_id, "pci%04x:%02x", &seg, &bus); + num = sscanf(dev_name(dev), "pci%04x:%02x", &seg, &bus); if (num != 2) return -ENODEV; *handle = acpi_get_pci_rootbridge_handle(seg, bus); @@ -288,21 +178,30 @@ static int pci_acpi_find_root_bridge(struct device *dev, acpi_handle *handle) return 0; } -static struct acpi_bus_type pci_acpi_bus = { +static struct acpi_bus_type acpi_pci_bus = { .bus = &pci_bus_type, - .find_device = pci_acpi_find_device, - .find_bridge = pci_acpi_find_root_bridge, + .find_device = acpi_pci_find_device, + .find_bridge = acpi_pci_find_root_bridge, }; -static int __init pci_acpi_init(void) +static int __init acpi_pci_init(void) { int ret; - ret = register_acpi_bus_type(&pci_acpi_bus); + if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_MSI) { + printk(KERN_INFO"ACPI FADT declares the system doesn't support MSI, so disable it\n"); + pci_no_msi(); + } + + if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) { + printk(KERN_INFO"ACPI FADT declares the system doesn't support PCIe ASPM, so disable it\n"); + pcie_no_aspm(); + } + + ret = register_acpi_bus_type(&acpi_pci_bus); if (ret) return 0; - platform_pci_choose_state = acpi_pci_choose_state; - platform_pci_set_power_state = acpi_pci_set_power_state; + pci_set_platform_pm(&acpi_pci_platform_pm); return 0; } -arch_initcall(pci_acpi_init); +arch_initcall(acpi_pci_init);