mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-03-30 10:55:03 +00:00
Merge branches 'acpi-pnp', 'acpi-soc', 'pm-domains' and 'pm-sleep'
* acpi-pnp: ACPI / PNP: Reserve ACPI resources at the fs_initcall_sync stage * acpi-soc: ACPI / LPSS: Fix up acpi_lpss_create_device() * pm-domains: PM / Domains: Avoid infinite loops in attach/detach code * pm-sleep: PM / hibernate: clarify resume documentation
This commit is contained in:
commit
d0aee67fa1
7 changed files with 45 additions and 207 deletions
|
@ -410,8 +410,17 @@ Documentation/usb/persist.txt.
|
||||||
|
|
||||||
Q: Can I suspend-to-disk using a swap partition under LVM?
|
Q: Can I suspend-to-disk using a swap partition under LVM?
|
||||||
|
|
||||||
A: No. You can suspend successfully, but you'll not be able to
|
A: Yes and No. You can suspend successfully, but the kernel will not be able
|
||||||
resume. uswsusp should be able to work with LVM. See suspend.sf.net.
|
to resume on its own. You need an initramfs that can recognize the resume
|
||||||
|
situation, activate the logical volume containing the swap volume (but not
|
||||||
|
touch any filesystems!), and eventually call
|
||||||
|
|
||||||
|
echo -n "$major:$minor" > /sys/power/resume
|
||||||
|
|
||||||
|
where $major and $minor are the respective major and minor device numbers of
|
||||||
|
the swap volume.
|
||||||
|
|
||||||
|
uswsusp works with LVM, too. See http://suspend.sourceforge.net/
|
||||||
|
|
||||||
Q: I upgraded the kernel from 2.6.15 to 2.6.16. Both kernels were
|
Q: I upgraded the kernel from 2.6.15 to 2.6.16. Both kernels were
|
||||||
compiled with the similar configuration files. Anyway I found that
|
compiled with the similar configuration files. Anyway I found that
|
||||||
|
|
|
@ -352,13 +352,16 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
|
||||||
pdata->mmio_size = resource_size(rentry->res);
|
pdata->mmio_size = resource_size(rentry->res);
|
||||||
pdata->mmio_base = ioremap(rentry->res->start,
|
pdata->mmio_base = ioremap(rentry->res->start,
|
||||||
pdata->mmio_size);
|
pdata->mmio_size);
|
||||||
if (!pdata->mmio_base)
|
|
||||||
goto err_out;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
acpi_dev_free_resource_list(&resource_list);
|
acpi_dev_free_resource_list(&resource_list);
|
||||||
|
|
||||||
|
if (!pdata->mmio_base) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
|
||||||
pdata->dev_desc = dev_desc;
|
pdata->dev_desc = dev_desc;
|
||||||
|
|
||||||
if (dev_desc->setup)
|
if (dev_desc->setup)
|
||||||
|
|
|
@ -175,10 +175,14 @@ static void __init acpi_request_region (struct acpi_generic_address *gas,
|
||||||
if (!addr || !length)
|
if (!addr || !length)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
acpi_reserve_region(addr, length, gas->space_id, 0, desc);
|
/* Resources are never freed */
|
||||||
|
if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_IO)
|
||||||
|
request_region(addr, length, desc);
|
||||||
|
else if (gas->space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
|
||||||
|
request_mem_region(addr, length, desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init acpi_reserve_resources(void)
|
static int __init acpi_reserve_resources(void)
|
||||||
{
|
{
|
||||||
acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length,
|
acpi_request_region(&acpi_gbl_FADT.xpm1a_event_block, acpi_gbl_FADT.pm1_event_length,
|
||||||
"ACPI PM1a_EVT_BLK");
|
"ACPI PM1a_EVT_BLK");
|
||||||
|
@ -207,7 +211,10 @@ static void __init acpi_reserve_resources(void)
|
||||||
if (!(acpi_gbl_FADT.gpe1_block_length & 0x1))
|
if (!(acpi_gbl_FADT.gpe1_block_length & 0x1))
|
||||||
acpi_request_region(&acpi_gbl_FADT.xgpe1_block,
|
acpi_request_region(&acpi_gbl_FADT.xgpe1_block,
|
||||||
acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK");
|
acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK");
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
fs_initcall_sync(acpi_reserve_resources);
|
||||||
|
|
||||||
void acpi_os_printf(const char *fmt, ...)
|
void acpi_os_printf(const char *fmt, ...)
|
||||||
{
|
{
|
||||||
|
@ -1862,7 +1869,6 @@ acpi_status __init acpi_os_initialize(void)
|
||||||
|
|
||||||
acpi_status __init acpi_os_initialize1(void)
|
acpi_status __init acpi_os_initialize1(void)
|
||||||
{
|
{
|
||||||
acpi_reserve_resources();
|
|
||||||
kacpid_wq = alloc_workqueue("kacpid", 0, 1);
|
kacpid_wq = alloc_workqueue("kacpid", 0, 1);
|
||||||
kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1);
|
kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1);
|
||||||
kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0);
|
kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0);
|
||||||
|
|
|
@ -26,7 +26,6 @@
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
#include <linux/ioport.h>
|
#include <linux/ioport.h>
|
||||||
#include <linux/list.h>
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
|
||||||
#ifdef CONFIG_X86
|
#ifdef CONFIG_X86
|
||||||
|
@ -622,164 +621,3 @@ int acpi_dev_filter_resource_type(struct acpi_resource *ares,
|
||||||
return (type & types) ? 0 : 1;
|
return (type & types) ? 0 : 1;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type);
|
EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type);
|
||||||
|
|
||||||
struct reserved_region {
|
|
||||||
struct list_head node;
|
|
||||||
u64 start;
|
|
||||||
u64 end;
|
|
||||||
};
|
|
||||||
|
|
||||||
static LIST_HEAD(reserved_io_regions);
|
|
||||||
static LIST_HEAD(reserved_mem_regions);
|
|
||||||
|
|
||||||
static int request_range(u64 start, u64 end, u8 space_id, unsigned long flags,
|
|
||||||
char *desc)
|
|
||||||
{
|
|
||||||
unsigned int length = end - start + 1;
|
|
||||||
struct resource *res;
|
|
||||||
|
|
||||||
res = space_id == ACPI_ADR_SPACE_SYSTEM_IO ?
|
|
||||||
request_region(start, length, desc) :
|
|
||||||
request_mem_region(start, length, desc);
|
|
||||||
if (!res)
|
|
||||||
return -EIO;
|
|
||||||
|
|
||||||
res->flags &= ~flags;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int add_region_before(u64 start, u64 end, u8 space_id,
|
|
||||||
unsigned long flags, char *desc,
|
|
||||||
struct list_head *head)
|
|
||||||
{
|
|
||||||
struct reserved_region *reg;
|
|
||||||
int error;
|
|
||||||
|
|
||||||
reg = kmalloc(sizeof(*reg), GFP_KERNEL);
|
|
||||||
if (!reg)
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
error = request_range(start, end, space_id, flags, desc);
|
|
||||||
if (error) {
|
|
||||||
kfree(reg);
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
reg->start = start;
|
|
||||||
reg->end = end;
|
|
||||||
list_add_tail(®->node, head);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* acpi_reserve_region - Reserve an I/O or memory region as a system resource.
|
|
||||||
* @start: Starting address of the region.
|
|
||||||
* @length: Length of the region.
|
|
||||||
* @space_id: Identifier of address space to reserve the region from.
|
|
||||||
* @flags: Resource flags to clear for the region after requesting it.
|
|
||||||
* @desc: Region description (for messages).
|
|
||||||
*
|
|
||||||
* Reserve an I/O or memory region as a system resource to prevent others from
|
|
||||||
* using it. If the new region overlaps with one of the regions (in the given
|
|
||||||
* address space) already reserved by this routine, only the non-overlapping
|
|
||||||
* parts of it will be reserved.
|
|
||||||
*
|
|
||||||
* Returned is either 0 (success) or a negative error code indicating a resource
|
|
||||||
* reservation problem. It is the code of the first encountered error, but the
|
|
||||||
* routine doesn't abort until it has attempted to request all of the parts of
|
|
||||||
* the new region that don't overlap with other regions reserved previously.
|
|
||||||
*
|
|
||||||
* The resources requested by this routine are never released.
|
|
||||||
*/
|
|
||||||
int acpi_reserve_region(u64 start, unsigned int length, u8 space_id,
|
|
||||||
unsigned long flags, char *desc)
|
|
||||||
{
|
|
||||||
struct list_head *regions;
|
|
||||||
struct reserved_region *reg;
|
|
||||||
u64 end = start + length - 1;
|
|
||||||
int ret = 0, error = 0;
|
|
||||||
|
|
||||||
if (space_id == ACPI_ADR_SPACE_SYSTEM_IO)
|
|
||||||
regions = &reserved_io_regions;
|
|
||||||
else if (space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY)
|
|
||||||
regions = &reserved_mem_regions;
|
|
||||||
else
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
if (list_empty(regions))
|
|
||||||
return add_region_before(start, end, space_id, flags, desc, regions);
|
|
||||||
|
|
||||||
list_for_each_entry(reg, regions, node)
|
|
||||||
if (reg->start == end + 1) {
|
|
||||||
/* The new region can be prepended to this one. */
|
|
||||||
ret = request_range(start, end, space_id, flags, desc);
|
|
||||||
if (!ret)
|
|
||||||
reg->start = start;
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
} else if (reg->start > end) {
|
|
||||||
/* No overlap. Add the new region here and get out. */
|
|
||||||
return add_region_before(start, end, space_id, flags,
|
|
||||||
desc, ®->node);
|
|
||||||
} else if (reg->end == start - 1) {
|
|
||||||
goto combine;
|
|
||||||
} else if (reg->end >= start) {
|
|
||||||
goto overlap;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* The new region goes after the last existing one. */
|
|
||||||
return add_region_before(start, end, space_id, flags, desc, regions);
|
|
||||||
|
|
||||||
overlap:
|
|
||||||
/*
|
|
||||||
* The new region overlaps an existing one.
|
|
||||||
*
|
|
||||||
* The head part of the new region immediately preceding the existing
|
|
||||||
* overlapping one can be combined with it right away.
|
|
||||||
*/
|
|
||||||
if (reg->start > start) {
|
|
||||||
error = request_range(start, reg->start - 1, space_id, flags, desc);
|
|
||||||
if (error)
|
|
||||||
ret = error;
|
|
||||||
else
|
|
||||||
reg->start = start;
|
|
||||||
}
|
|
||||||
|
|
||||||
combine:
|
|
||||||
/*
|
|
||||||
* The new region is adjacent to an existing one. If it extends beyond
|
|
||||||
* that region all the way to the next one, it is possible to combine
|
|
||||||
* all three of them.
|
|
||||||
*/
|
|
||||||
while (reg->end < end) {
|
|
||||||
struct reserved_region *next = NULL;
|
|
||||||
u64 a = reg->end + 1, b = end;
|
|
||||||
|
|
||||||
if (!list_is_last(®->node, regions)) {
|
|
||||||
next = list_next_entry(reg, node);
|
|
||||||
if (next->start <= end)
|
|
||||||
b = next->start - 1;
|
|
||||||
}
|
|
||||||
error = request_range(a, b, space_id, flags, desc);
|
|
||||||
if (!error) {
|
|
||||||
if (next && next->start == b + 1) {
|
|
||||||
reg->end = next->end;
|
|
||||||
list_del(&next->node);
|
|
||||||
kfree(next);
|
|
||||||
} else {
|
|
||||||
reg->end = end;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (next) {
|
|
||||||
if (!ret)
|
|
||||||
ret = error;
|
|
||||||
|
|
||||||
reg = next;
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret ? ret : error;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(acpi_reserve_region);
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
* This file is released under the GPLv2.
|
* This file is released under the GPLv2.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/io.h>
|
#include <linux/io.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
@ -19,6 +20,8 @@
|
||||||
#include <linux/suspend.h>
|
#include <linux/suspend.h>
|
||||||
#include <linux/export.h>
|
#include <linux/export.h>
|
||||||
|
|
||||||
|
#define GENPD_RETRY_MAX_MS 250 /* Approximate */
|
||||||
|
|
||||||
#define GENPD_DEV_CALLBACK(genpd, type, callback, dev) \
|
#define GENPD_DEV_CALLBACK(genpd, type, callback, dev) \
|
||||||
({ \
|
({ \
|
||||||
type (*__routine)(struct device *__d); \
|
type (*__routine)(struct device *__d); \
|
||||||
|
@ -2131,6 +2134,7 @@ EXPORT_SYMBOL_GPL(of_genpd_get_from_provider);
|
||||||
static void genpd_dev_pm_detach(struct device *dev, bool power_off)
|
static void genpd_dev_pm_detach(struct device *dev, bool power_off)
|
||||||
{
|
{
|
||||||
struct generic_pm_domain *pd;
|
struct generic_pm_domain *pd;
|
||||||
|
unsigned int i;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
pd = pm_genpd_lookup_dev(dev);
|
pd = pm_genpd_lookup_dev(dev);
|
||||||
|
@ -2139,10 +2143,12 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off)
|
||||||
|
|
||||||
dev_dbg(dev, "removing from PM domain %s\n", pd->name);
|
dev_dbg(dev, "removing from PM domain %s\n", pd->name);
|
||||||
|
|
||||||
while (1) {
|
for (i = 1; i < GENPD_RETRY_MAX_MS; i <<= 1) {
|
||||||
ret = pm_genpd_remove_device(pd, dev);
|
ret = pm_genpd_remove_device(pd, dev);
|
||||||
if (ret != -EAGAIN)
|
if (ret != -EAGAIN)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
mdelay(i);
|
||||||
cond_resched();
|
cond_resched();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2183,6 +2189,7 @@ int genpd_dev_pm_attach(struct device *dev)
|
||||||
{
|
{
|
||||||
struct of_phandle_args pd_args;
|
struct of_phandle_args pd_args;
|
||||||
struct generic_pm_domain *pd;
|
struct generic_pm_domain *pd;
|
||||||
|
unsigned int i;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!dev->of_node)
|
if (!dev->of_node)
|
||||||
|
@ -2218,10 +2225,12 @@ int genpd_dev_pm_attach(struct device *dev)
|
||||||
|
|
||||||
dev_dbg(dev, "adding to PM domain %s\n", pd->name);
|
dev_dbg(dev, "adding to PM domain %s\n", pd->name);
|
||||||
|
|
||||||
while (1) {
|
for (i = 1; i < GENPD_RETRY_MAX_MS; i <<= 1) {
|
||||||
ret = pm_genpd_add_device(pd, dev);
|
ret = pm_genpd_add_device(pd, dev);
|
||||||
if (ret != -EAGAIN)
|
if (ret != -EAGAIN)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
mdelay(i);
|
||||||
cond_resched();
|
cond_resched();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
* Bjorn Helgaas <bjorn.helgaas@hp.com>
|
* Bjorn Helgaas <bjorn.helgaas@hp.com>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/acpi.h>
|
|
||||||
#include <linux/pnp.h>
|
#include <linux/pnp.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
|
@ -23,41 +22,25 @@ static const struct pnp_device_id pnp_dev_table[] = {
|
||||||
{"", 0}
|
{"", 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_ACPI
|
|
||||||
static bool __reserve_range(u64 start, unsigned int length, bool io, char *desc)
|
|
||||||
{
|
|
||||||
u8 space_id = io ? ACPI_ADR_SPACE_SYSTEM_IO : ACPI_ADR_SPACE_SYSTEM_MEMORY;
|
|
||||||
return !acpi_reserve_region(start, length, space_id, IORESOURCE_BUSY, desc);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static bool __reserve_range(u64 start, unsigned int length, bool io, char *desc)
|
|
||||||
{
|
|
||||||
struct resource *res;
|
|
||||||
|
|
||||||
res = io ? request_region(start, length, desc) :
|
|
||||||
request_mem_region(start, length, desc);
|
|
||||||
if (res) {
|
|
||||||
res->flags &= ~IORESOURCE_BUSY;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void reserve_range(struct pnp_dev *dev, struct resource *r, int port)
|
static void reserve_range(struct pnp_dev *dev, struct resource *r, int port)
|
||||||
{
|
{
|
||||||
char *regionid;
|
char *regionid;
|
||||||
const char *pnpid = dev_name(&dev->dev);
|
const char *pnpid = dev_name(&dev->dev);
|
||||||
resource_size_t start = r->start, end = r->end;
|
resource_size_t start = r->start, end = r->end;
|
||||||
bool reserved;
|
struct resource *res;
|
||||||
|
|
||||||
regionid = kmalloc(16, GFP_KERNEL);
|
regionid = kmalloc(16, GFP_KERNEL);
|
||||||
if (!regionid)
|
if (!regionid)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
snprintf(regionid, 16, "pnp %s", pnpid);
|
snprintf(regionid, 16, "pnp %s", pnpid);
|
||||||
reserved = __reserve_range(start, end - start + 1, !!port, regionid);
|
if (port)
|
||||||
if (!reserved)
|
res = request_region(start, end - start + 1, regionid);
|
||||||
|
else
|
||||||
|
res = request_mem_region(start, end - start + 1, regionid);
|
||||||
|
if (res)
|
||||||
|
res->flags &= ~IORESOURCE_BUSY;
|
||||||
|
else
|
||||||
kfree(regionid);
|
kfree(regionid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -66,7 +49,7 @@ static void reserve_range(struct pnp_dev *dev, struct resource *r, int port)
|
||||||
* have double reservations.
|
* have double reservations.
|
||||||
*/
|
*/
|
||||||
dev_info(&dev->dev, "%pR %s reserved\n", r,
|
dev_info(&dev->dev, "%pR %s reserved\n", r,
|
||||||
reserved ? "has been" : "could not be");
|
res ? "has been" : "could not be");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reserve_resources_of_dev(struct pnp_dev *dev)
|
static void reserve_resources_of_dev(struct pnp_dev *dev)
|
||||||
|
|
|
@ -309,9 +309,6 @@ int acpi_check_region(resource_size_t start, resource_size_t n,
|
||||||
|
|
||||||
int acpi_resources_are_enforced(void);
|
int acpi_resources_are_enforced(void);
|
||||||
|
|
||||||
int acpi_reserve_region(u64 start, unsigned int length, u8 space_id,
|
|
||||||
unsigned long flags, char *desc);
|
|
||||||
|
|
||||||
#ifdef CONFIG_HIBERNATION
|
#ifdef CONFIG_HIBERNATION
|
||||||
void __init acpi_no_s4_hw_signature(void);
|
void __init acpi_no_s4_hw_signature(void);
|
||||||
#endif
|
#endif
|
||||||
|
@ -507,13 +504,6 @@ static inline int acpi_check_region(resource_size_t start, resource_size_t n,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int acpi_reserve_region(u64 start, unsigned int length,
|
|
||||||
u8 space_id, unsigned long flags,
|
|
||||||
char *desc)
|
|
||||||
{
|
|
||||||
return -ENXIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct acpi_table_header;
|
struct acpi_table_header;
|
||||||
static inline int acpi_table_parse(char *id,
|
static inline int acpi_table_parse(char *id,
|
||||||
int (*handler)(struct acpi_table_header *))
|
int (*handler)(struct acpi_table_header *))
|
||||||
|
|
Loading…
Add table
Reference in a new issue