diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c index 93d160661f4c..d1dd0ada14b7 100644 --- a/drivers/acpi/acpi_lpss.c +++ b/drivers/acpi/acpi_lpss.c @@ -1,7 +1,7 @@ /* * ACPI support for Intel Lynxpoint LPSS. * - * Copyright (C) 2013, Intel Corporation + * Copyright (C) 2013, 2014, Intel Corporation * Authors: Mika Westerberg * Rafael J. Wysocki * @@ -60,6 +60,8 @@ ACPI_MODULE_NAME("acpi_lpss"); #define LPSS_CLK_DIVIDER BIT(2) #define LPSS_LTR BIT(3) #define LPSS_SAVE_CTX BIT(4) +#define LPSS_DEV_PROXY BIT(5) +#define LPSS_PROXY_REQ BIT(6) struct lpss_private_data; @@ -70,8 +72,10 @@ struct lpss_device_desc { void (*setup)(struct lpss_private_data *pdata); }; +static struct device *proxy_device; + static struct lpss_device_desc lpss_dma_desc = { - .flags = LPSS_CLK, + .flags = LPSS_CLK | LPSS_PROXY_REQ, }; struct lpss_private_data { @@ -146,22 +150,24 @@ static struct lpss_device_desc byt_pwm_dev_desc = { }; static struct lpss_device_desc byt_uart_dev_desc = { - .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX, + .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX | + LPSS_DEV_PROXY, .prv_offset = 0x800, .setup = lpss_uart_setup, }; static struct lpss_device_desc byt_spi_dev_desc = { - .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX, + .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX | + LPSS_DEV_PROXY, .prv_offset = 0x400, }; static struct lpss_device_desc byt_sdio_dev_desc = { - .flags = LPSS_CLK, + .flags = LPSS_CLK | LPSS_DEV_PROXY, }; static struct lpss_device_desc byt_i2c_dev_desc = { - .flags = LPSS_CLK | LPSS_SAVE_CTX, + .flags = LPSS_CLK | LPSS_SAVE_CTX | LPSS_DEV_PROXY, .prv_offset = 0x800, .setup = byt_i2c_setup, }; @@ -368,6 +374,8 @@ static int acpi_lpss_create_device(struct acpi_device *adev, adev->driver_data = pdata; pdev = acpi_create_platform_device(adev); if (!IS_ERR_OR_NULL(pdev)) { + if (!proxy_device && dev_desc->flags & LPSS_DEV_PROXY) + proxy_device = &pdev->dev; return 1; } @@ -499,14 +507,15 @@ static void acpi_lpss_set_ltr(struct device *dev, s32 val) /** * acpi_lpss_save_ctx() - Save the private registers of LPSS device * @dev: LPSS device + * @pdata: pointer to the private data of the LPSS device * * Most LPSS devices have private registers which may loose their context when * the device is powered down. acpi_lpss_save_ctx() saves those registers into * prv_reg_ctx array. */ -static void acpi_lpss_save_ctx(struct device *dev) +static void acpi_lpss_save_ctx(struct device *dev, + struct lpss_private_data *pdata) { - struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); unsigned int i; for (i = 0; i < LPSS_PRV_REG_COUNT; i++) { @@ -521,12 +530,13 @@ static void acpi_lpss_save_ctx(struct device *dev) /** * acpi_lpss_restore_ctx() - Restore the private registers of LPSS device * @dev: LPSS device + * @pdata: pointer to the private data of the LPSS device * * Restores the registers that were previously stored with acpi_lpss_save_ctx(). */ -static void acpi_lpss_restore_ctx(struct device *dev) +static void acpi_lpss_restore_ctx(struct device *dev, + struct lpss_private_data *pdata) { - struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); unsigned int i; /* @@ -549,23 +559,31 @@ static void acpi_lpss_restore_ctx(struct device *dev) #ifdef CONFIG_PM_SLEEP static int acpi_lpss_suspend_late(struct device *dev) { - int ret = pm_generic_suspend_late(dev); + struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); + int ret; + ret = pm_generic_suspend_late(dev); if (ret) return ret; - acpi_lpss_save_ctx(dev); + if (pdata->dev_desc->flags & LPSS_SAVE_CTX) + acpi_lpss_save_ctx(dev, pdata); + return acpi_dev_suspend_late(dev); } static int acpi_lpss_resume_early(struct device *dev) { - int ret = acpi_dev_resume_early(dev); + struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); + int ret; + ret = acpi_dev_resume_early(dev); if (ret) return ret; - acpi_lpss_restore_ctx(dev); + if (pdata->dev_desc->flags & LPSS_SAVE_CTX) + acpi_lpss_restore_ctx(dev, pdata); + return pm_generic_resume_early(dev); } #endif /* CONFIG_PM_SLEEP */ @@ -573,23 +591,44 @@ static int acpi_lpss_resume_early(struct device *dev) #ifdef CONFIG_PM_RUNTIME static int acpi_lpss_runtime_suspend(struct device *dev) { - int ret = pm_generic_runtime_suspend(dev); + struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); + int ret; + ret = pm_generic_runtime_suspend(dev); if (ret) return ret; - acpi_lpss_save_ctx(dev); - return acpi_dev_runtime_suspend(dev); + if (pdata->dev_desc->flags & LPSS_SAVE_CTX) + acpi_lpss_save_ctx(dev, pdata); + + ret = acpi_dev_runtime_suspend(dev); + if (ret) + return ret; + + if (pdata->dev_desc->flags & LPSS_PROXY_REQ && proxy_device) + return pm_runtime_put_sync_suspend(proxy_device); + + return 0; } static int acpi_lpss_runtime_resume(struct device *dev) { - int ret = acpi_dev_runtime_resume(dev); + struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); + int ret; + if (pdata->dev_desc->flags & LPSS_PROXY_REQ && proxy_device) { + ret = pm_runtime_get_sync(proxy_device); + if (ret) + return ret; + } + + ret = acpi_dev_runtime_resume(dev); if (ret) return ret; - acpi_lpss_restore_ctx(dev); + if (pdata->dev_desc->flags & LPSS_SAVE_CTX) + acpi_lpss_restore_ctx(dev, pdata); + return pm_generic_runtime_resume(dev); } #endif /* CONFIG_PM_RUNTIME */ @@ -631,30 +670,27 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb, return 0; pdata = acpi_driver_data(adev); - if (!pdata || !pdata->mmio_base) + if (!pdata) return 0; - if (pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) { + if (pdata->mmio_base && + pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) { dev_err(&pdev->dev, "MMIO size insufficient to access LTR\n"); return 0; } switch (action) { - case BUS_NOTIFY_BOUND_DRIVER: - if (pdata->dev_desc->flags & LPSS_SAVE_CTX) - pdev->dev.pm_domain = &acpi_lpss_pm_domain; - break; - case BUS_NOTIFY_UNBOUND_DRIVER: - if (pdata->dev_desc->flags & LPSS_SAVE_CTX) - pdev->dev.pm_domain = NULL; - break; case BUS_NOTIFY_ADD_DEVICE: + pdev->dev.pm_domain = &acpi_lpss_pm_domain; if (pdata->dev_desc->flags & LPSS_LTR) return sysfs_create_group(&pdev->dev.kobj, &lpss_attr_group); + break; case BUS_NOTIFY_DEL_DEVICE: if (pdata->dev_desc->flags & LPSS_LTR) sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group); + pdev->dev.pm_domain = NULL; + break; default: break; } diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c index 8ec8a89a20ab..d98ba4355819 100644 --- a/drivers/acpi/battery.c +++ b/drivers/acpi/battery.c @@ -1180,6 +1180,10 @@ static int acpi_battery_add(struct acpi_device *device) if (!device) return -EINVAL; + + if (device->dep_unmet) + return -EPROBE_DEFER; + battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL); if (!battery) return -ENOMEM; diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index 7db193160766..076af8149566 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -201,7 +201,7 @@ int acpi_device_set_power(struct acpi_device *device, int state) * Transition Power * ---------------- * In accordance with the ACPI specification first apply power (via - * power resources) and then evalute _PSx. + * power resources) and then evaluate _PSx. */ if (device->power.flags.power_resources) { result = acpi_power_transition(device, state); diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 17f9ec501972..38472fd5d104 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -334,10 +334,10 @@ static int acpi_processor_get_power_info_default(struct acpi_processor *pr) static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) { - acpi_status status = 0; + acpi_status status; u64 count; int current_count; - int i; + int i, ret = 0; struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL }; union acpi_object *cst; @@ -358,7 +358,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) /* There must be at least 2 elements */ if (!cst || (cst->type != ACPI_TYPE_PACKAGE) || cst->package.count < 2) { printk(KERN_ERR PREFIX "not enough elements in _CST\n"); - status = -EFAULT; + ret = -EFAULT; goto end; } @@ -367,7 +367,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) /* Validate number of power states. */ if (count < 1 || count != cst->package.count - 1) { printk(KERN_ERR PREFIX "count given by _CST is not valid\n"); - status = -EFAULT; + ret = -EFAULT; goto end; } @@ -489,12 +489,12 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr) /* Validate number of power states discovered */ if (current_count < 2) - status = -EFAULT; + ret = -EFAULT; end: kfree(buffer.pointer); - return status; + return ret; } static void acpi_processor_power_verify_c3(struct acpi_processor *pr, @@ -1111,7 +1111,7 @@ static int acpi_processor_registered; int acpi_processor_power_init(struct acpi_processor *pr) { - acpi_status status = 0; + acpi_status status; int retval; struct cpuidle_device *dev; static int first_run; diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 9cb5cca3cfe3..1b1cf558d3d3 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -36,6 +36,8 @@ bool acpi_force_hot_remove; static const char *dummy_hid = "device"; +static LIST_HEAD(acpi_dep_list); +static DEFINE_MUTEX(acpi_dep_list_lock); static LIST_HEAD(acpi_bus_id_list); static DEFINE_MUTEX(acpi_scan_lock); static LIST_HEAD(acpi_scan_handlers_list); @@ -43,6 +45,12 @@ DEFINE_MUTEX(acpi_device_lock); LIST_HEAD(acpi_wakeup_device_list); static DEFINE_MUTEX(acpi_hp_context_lock); +struct acpi_dep_data { + struct list_head node; + acpi_handle master; + acpi_handle slave; +}; + struct acpi_device_bus_id{ char bus_id[15]; unsigned int instance_no; @@ -2193,6 +2201,59 @@ static void acpi_scan_init_hotplug(struct acpi_device *adev) } } +static void acpi_device_dep_initialize(struct acpi_device *adev) +{ + struct acpi_dep_data *dep; + struct acpi_handle_list dep_devices; + acpi_status status; + int i; + + if (!acpi_has_method(adev->handle, "_DEP")) + return; + + status = acpi_evaluate_reference(adev->handle, "_DEP", NULL, + &dep_devices); + if (ACPI_FAILURE(status)) { + dev_err(&adev->dev, "Failed to evaluate _DEP.\n"); + return; + } + + for (i = 0; i < dep_devices.count; i++) { + struct acpi_device_info *info; + int skip; + + status = acpi_get_object_info(dep_devices.handles[i], &info); + if (ACPI_FAILURE(status)) { + dev_err(&adev->dev, "Error reading device info\n"); + continue; + } + + /* + * Skip the dependency of Windows System Power + * Management Controller + */ + skip = info->valid & ACPI_VALID_HID && + !strcmp(info->hardware_id.string, "INT3396"); + + kfree(info); + + if (skip) + continue; + + dep = kzalloc(sizeof(struct acpi_dep_data), GFP_KERNEL); + if (!dep) + return; + + dep->master = dep_devices.handles[i]; + dep->slave = adev->handle; + adev->dep_unmet++; + + mutex_lock(&acpi_dep_list_lock); + list_add_tail(&dep->node , &acpi_dep_list); + mutex_unlock(&acpi_dep_list_lock); + } +} + static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, void *not_used, void **return_value) { @@ -2219,6 +2280,7 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, return AE_CTRL_DEPTH; acpi_scan_init_hotplug(device); + acpi_device_dep_initialize(device); out: if (!*return_value) @@ -2339,6 +2401,29 @@ static void acpi_bus_attach(struct acpi_device *device) device->handler->hotplug.notify_online(device); } +void acpi_walk_dep_device_list(acpi_handle handle) +{ + struct acpi_dep_data *dep, *tmp; + struct acpi_device *adev; + + mutex_lock(&acpi_dep_list_lock); + list_for_each_entry_safe(dep, tmp, &acpi_dep_list, node) { + if (dep->master == handle) { + acpi_bus_get_device(dep->slave, &adev); + if (!adev) + continue; + + adev->dep_unmet--; + if (!adev->dep_unmet) + acpi_bus_attach(adev); + list_del(&dep->node); + kfree(dep); + } + } + mutex_unlock(&acpi_dep_list_lock); +} +EXPORT_SYMBOL_GPL(acpi_walk_dep_device_list); + /** * acpi_bus_scan - Add ACPI device node objects in a given namespace scope. * @handle: Root of the namespace scope to scan. diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c index 05a31b573fc3..8aa9254a387f 100644 --- a/drivers/acpi/sleep.c +++ b/drivers/acpi/sleep.c @@ -630,6 +630,7 @@ static int acpi_freeze_begin(void) static int acpi_freeze_prepare(void) { acpi_enable_all_wakeup_gpes(); + acpi_os_wait_events_complete(); enable_irq_wake(acpi_gbl_FADT.sci_interrupt); return 0; } @@ -825,6 +826,7 @@ static void acpi_power_off_prepare(void) /* Prepare to power off the system */ acpi_sleep_prepare(ACPI_STATE_S5); acpi_disable_all_gpes(); + acpi_os_wait_events_complete(); } static void acpi_power_off(void) diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c index 244722170410..380478562b7d 100644 --- a/drivers/dma/dw/core.c +++ b/drivers/dma/dw/core.c @@ -22,6 +22,7 @@ #include #include #include +#include #include "../dmaengine.h" #include "internal.h" @@ -1504,6 +1505,9 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata) dw->regs = chip->regs; chip->dw = dw; + pm_runtime_enable(chip->dev); + pm_runtime_get_sync(chip->dev); + dw_params = dma_read_byaddr(chip->regs, DW_PARAMS); autocfg = dw_params >> DW_PARAMS_EN & 0x1; @@ -1667,11 +1671,14 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata) dev_info(chip->dev, "DesignWare DMA Controller, %d channels\n", nr_channels); + pm_runtime_put_sync_suspend(chip->dev); + return 0; err_dma_register: free_irq(chip->irq, dw); err_pdata: + pm_runtime_put_sync_suspend(chip->dev); return err; } EXPORT_SYMBOL_GPL(dw_dma_probe); @@ -1681,6 +1688,8 @@ int dw_dma_remove(struct dw_dma_chip *chip) struct dw_dma *dw = chip->dw; struct dw_dma_chan *dwc, *_dwc; + pm_runtime_get_sync(chip->dev); + dw_dma_off(dw); dma_async_device_unregister(&dw->dma); @@ -1693,6 +1702,8 @@ int dw_dma_remove(struct dw_dma_chip *chip) channel_clear_bit(dw, CH_EN, dwc->mask); } + pm_runtime_put_sync_suspend(chip->dev); + pm_runtime_disable(chip->dev); return 0; } EXPORT_SYMBOL_GPL(dw_dma_remove); diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index f43b4e11647a..68aeb8eedae0 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c @@ -403,6 +403,7 @@ static int acpi_i2c_install_space_handler(struct i2c_adapter *adapter) return -ENOMEM; } + acpi_walk_dep_device_list(handle); return 0; } diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 7d1ce40e201e..d53908438e95 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -372,6 +372,7 @@ struct acpi_device { void *driver_data; struct device dev; unsigned int physical_node_count; + unsigned int dep_unmet; struct list_head physical_node_list; struct mutex physical_node_lock; void (*remove)(struct acpi_device *); diff --git a/include/acpi/processor.h b/include/acpi/processor.h index 9b9b6f29bbf3..3ca9b751f122 100644 --- a/include/acpi/processor.h +++ b/include/acpi/processor.h @@ -67,9 +67,6 @@ struct acpi_processor_cx { }; struct acpi_processor_power { - struct acpi_processor_cx *state; - unsigned long bm_check_timestamp; - u32 default_state; int count; struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER]; int timer_broadcast_on_state; @@ -313,11 +310,13 @@ static inline int acpi_processor_get_bios_limit(int cpu, unsigned int *limit) #endif /* CONFIG_CPU_FREQ */ /* in processor_core.c */ -void acpi_processor_set_pdc(acpi_handle handle); int acpi_get_apicid(acpi_handle, int type, u32 acpi_id); int acpi_map_cpuid(int apic_id, u32 acpi_id); int acpi_get_cpuid(acpi_handle, int type, u32 acpi_id); +/* in processor_pdc.c */ +void acpi_processor_set_pdc(acpi_handle handle); + /* in processor_throttling.c */ int acpi_processor_tstate_has_changed(struct acpi_processor *pr); int acpi_processor_get_throttling_info(struct acpi_processor *pr); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index 0ccaa093010c..d7a5fcf9ef0f 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -432,6 +432,7 @@ extern bool acpi_driver_match_device(struct device *dev, const struct device_driver *drv); int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *); int acpi_device_modalias(struct device *, char *, int); +void acpi_walk_dep_device_list(acpi_handle handle); struct platform_device *acpi_create_platform_device(struct acpi_device *); #define ACPI_PTR(_ptr) (_ptr)