Re: [PATCH] ACPI / PNP: Reserve ACPI resources at the fs_initcall_sync stage
From: George McCollister
Date: Wed Sep 16 2015 - 17:45:59 EST
Unfortunately I just got around to trying linux 4.1.6 (which contains
this commit) on the Versalogic Tiger (VL-EPM-24)
http://www.versalogic.com/tiger and this commit breaks it, seems to be
back to the old behavior reported here:
http://marc.info/?t=143092384600002&r=1&w=2
Before reversing the commit it shows:
pci 0000:00:1c.0: BAR 13: assigned [io 0x2000-0x2fff]
After reversing the commit it shows:
pci 0000:00:1c.0: BAR 13: assigned [io 0x3000-0x3fff]
I don't have a solution to propose at this point and haven't tried the
latest upstream so I'll just be building with this commit reversed
(which solves the problem) until I have a chance to look into this
further.
Regards,
George McCollister
On Fri, Jul 3, 2015 at 8:09 PM, Rafael J. Wysocki <rjw@xxxxxxxxxxxxx> wrote:
> From: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>
>
> This effectively reverts the following three commits:
>
> 7bc10388ccdd ACPI / resources: free memory on error in add_region_before()
> 0f1b414d1907 ACPI / PNP: Avoid conflicting resource reservations
> b9a5e5e18fbf ACPI / init: Fix the ordering of acpi_reserve_resources()
>
> (commit b9a5e5e18fbf introduced regressions some of which, but not
> all, were addressed by commit 0f1b414d1907 and commit 7bc10388ccdd
> was a fixup on top of the latter) and causes ACPI fixed hardware
> resources to be reserved at the fs_initcall_sync stage of system
> initialization.
>
> The story is as follows. First, a boot regression was reported due
> to an apparent resource reservation ordering change after a commit
> that shouldn't lead to such changes. Investigation led to the
> conclusion that the problem happened because acpi_reserve_resources()
> was executed at the device_initcall() stage of system initialization
> which wasn't strictly ordered with respect to driver initialization
> (and with respect to the initialization of the pcieport driver in
> particular), so a random change causing the device initcalls to be
> run in a different order might break things.
>
> The response to that was to attempt to run acpi_reserve_resources()
> as soon as we knew that ACPI would be in use (commit b9a5e5e18fbf).
> However, that turned out to be too early, because it caused resource
> reservations made by the PNP system driver to fail on at least one
> system and that failure was addressed by commit 0f1b414d1907.
>
> That fix still turned out to be insufficient, though, because
> calling acpi_reserve_resources() before the fs_initcall stage of
> system initialization caused a boot regression to happen on the
> eCAFE EC-800-H20G/S netbook. That meant that we only could call
> acpi_reserve_resources() at the fs_initcall initialization stage
> or later, but then we might just as well call it after the PNP
> initalization in which case commit 0f1b414d1907 wouldn't be
> necessary any more.
>
> For this reason, the changes made by commit 0f1b414d1907 are reverted
> (along with a memory leak fixup on top of that commit), the changes
> made by commit b9a5e5e18fbf that went too far are reverted too and
> acpi_reserve_resources() is changed into fs_initcall_sync, which
> will cause it to be executed after the PNP subsystem initialization
> (which is an fs_initcall) and before device initcalls (including
> the pcieport driver initialization) which should avoid the initial
> issue.
>
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=100581
> Link: http://marc.info/?t=143092384600002&r=1&w=2
> Link: https://bugzilla.kernel.org/show_bug.cgi?id=99831
> Link: http://marc.info/?t=143389402600001&r=1&w=2
> Fixes: b9a5e5e18fbf "ACPI / init: Fix the ordering of acpi_reserve_resources()"
> Reported-by: Roland Dreier <roland@xxxxxxxxxxxxxxx>
> Reported-by-and-tested-by: <g5983969@xxxxxxxxx>
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@xxxxxxxxx>
> ---
> drivers/acpi/osl.c | 12 ++-
> drivers/acpi/resource.c | 162 ------------------------------------------------
> drivers/pnp/system.c | 35 ++--------
> include/linux/acpi.h | 10 --
> 4 files changed, 18 insertions(+), 201 deletions(-)
>
> Index: linux-pm/drivers/acpi/resource.c
> ===================================================================
> --- linux-pm.orig/drivers/acpi/resource.c
> +++ linux-pm/drivers/acpi/resource.c
> @@ -26,7 +26,6 @@
> #include <linux/device.h>
> #include <linux/export.h>
> #include <linux/ioport.h>
> -#include <linux/list.h>
> #include <linux/slab.h>
>
> #ifdef CONFIG_X86
> @@ -622,164 +621,3 @@ int acpi_dev_filter_resource_type(struct
> return (type & types) ? 0 : 1;
> }
> 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);
> Index: linux-pm/drivers/acpi/osl.c
> ===================================================================
> --- linux-pm.orig/drivers/acpi/osl.c
> +++ linux-pm/drivers/acpi/osl.c
> @@ -175,10 +175,14 @@ static void __init acpi_request_region (
> if (!addr || !length)
> 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 PM1a_EVT_BLK");
> @@ -207,7 +211,10 @@ static void __init acpi_reserve_resource
> if (!(acpi_gbl_FADT.gpe1_block_length & 0x1))
> acpi_request_region(&acpi_gbl_FADT.xgpe1_block,
> acpi_gbl_FADT.gpe1_block_length, "ACPI GPE1_BLK");
> +
> + return 0;
> }
> +fs_initcall_sync(acpi_reserve_resources);
>
> void acpi_os_printf(const char *fmt, ...)
> {
> @@ -1862,7 +1869,6 @@ acpi_status __init acpi_os_initialize(vo
>
> acpi_status __init acpi_os_initialize1(void)
> {
> - acpi_reserve_resources();
> kacpid_wq = alloc_workqueue("kacpid", 0, 1);
> kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1);
> kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0);
> Index: linux-pm/drivers/pnp/system.c
> ===================================================================
> --- linux-pm.orig/drivers/pnp/system.c
> +++ linux-pm/drivers/pnp/system.c
> @@ -7,7 +7,6 @@
> * Bjorn Helgaas <bjorn.helgaas@xxxxxx>
> */
>
> -#include <linux/acpi.h>
> #include <linux/pnp.h>
> #include <linux/device.h>
> #include <linux/init.h>
> @@ -23,41 +22,25 @@ static const struct pnp_device_id pnp_de
> {"", 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)
> {
> char *regionid;
> const char *pnpid = dev_name(&dev->dev);
> resource_size_t start = r->start, end = r->end;
> - bool reserved;
> + struct resource *res;
>
> regionid = kmalloc(16, GFP_KERNEL);
> if (!regionid)
> return;
>
> snprintf(regionid, 16, "pnp %s", pnpid);
> - reserved = __reserve_range(start, end - start + 1, !!port, regionid);
> - if (!reserved)
> + if (port)
> + 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);
>
> /*
> @@ -66,7 +49,7 @@ static void reserve_range(struct pnp_dev
> * have double reservations.
> */
> 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)
> Index: linux-pm/include/linux/acpi.h
> ===================================================================
> --- linux-pm.orig/include/linux/acpi.h
> +++ linux-pm/include/linux/acpi.h
> @@ -309,9 +309,6 @@ int acpi_check_region(resource_size_t st
>
> 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
> void __init acpi_no_s4_hw_signature(void);
> #endif
> @@ -507,13 +504,6 @@ static inline int acpi_check_region(reso
> 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;
> static inline int acpi_table_parse(char *id,
> int (*handler)(struct acpi_table_header *))
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/