Re: 174cc7187e6f ACPICA: Tables: Back port acpi_get_table_with_size() and early_acpi_os_unmap_memory() from Linux kernel

From: Rafael J. Wysocki
Date: Tue Jan 10 2017 - 22:42:27 EST


On Tue, Jan 10, 2017 at 10:41 AM, Borislav Petkov <bp@xxxxxxxxx> wrote:
> On Tue, Jan 10, 2017 at 02:27:16AM +0100, Rafael J. Wysocki wrote:
>> Well, if the https://patchwork.kernel.org/patch/9504277/ patch from Lv
>> worked, the attached one should work too (please test), but it can be
>> justified in a slightly more convincing way.
>
> No workie:
>
> diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
> index 57fb5f4..acb6118 100644
> --- a/drivers/acpi/osl.c
> +++ b/drivers/acpi/osl.c
> @@ -378,7 +378,11 @@ static void acpi_os_drop_map_ref(struct acpi_ioremap *map)
> static void acpi_os_map_cleanup(struct acpi_ioremap *map)
> {
> if (!map->refcount) {
> - synchronize_rcu_expedited();
> + if (acpi_os_initialized) {
> + pr_err("%s: acpi_os_initialized\n", __func__);
> + synchronize_rcu_expedited();
> + }
> +
> acpi_unmap(map->phys, map->virt);
> kfree(map);
> }
>
> The pr_err() gets issued before the box hangs.
>
> Lv's version which set the bool in acpi_os_map_generic_address() did
> work though.

Well, it would if nothing mapped by acpi_os_map_generic_address() was
in the memory address space, for example, but then it would never use
the RCU synchronization as well (not good).

Basically, we need to find a point during the initialization such that
acpi_os_read/write_memory() is not invoked earlier and set a flag in
there.

Let's try the attached one.

BTW, I'm going to travel to the LCA starting tomorrow, so I guess I
will be a bit unresponsive during the next few days.

Thanks,
Rafael
---
drivers/acpi/bus.c | 6 ++++++
drivers/acpi/osl.c | 9 ++++++++-
include/acpi/acpi_io.h | 1 +
3 files changed, 15 insertions(+), 1 deletion(-)

Index: linux-pm/drivers/acpi/bus.c
===================================================================
--- linux-pm.orig/drivers/acpi/bus.c
+++ linux-pm/drivers/acpi/bus.c
@@ -1191,6 +1191,12 @@ static int __init acpi_init(void)
acpi_kobj = NULL;
}

+ /*
+ * acpi_os_read_memory()/acpi_os_write_memory() should not be invoked
+ * before this point.
+ */
+ acpi_sync_memory_unmap = true;
+
init_acpi_device_notify();
result = acpi_bus_init();
if (result) {
Index: linux-pm/drivers/acpi/osl.c
===================================================================
--- linux-pm.orig/drivers/acpi/osl.c
+++ linux-pm/drivers/acpi/osl.c
@@ -77,6 +77,7 @@ static struct workqueue_struct *kacpi_ho
static bool acpi_os_initialized;
unsigned int acpi_sci_irq = INVALID_ACPI_IRQ;
bool acpi_permanent_mmap = false;
+bool acpi_sync_memory_unmap;

/*
* This list of permanent mappings is for memory that may be accessed from
@@ -378,7 +379,9 @@ static void acpi_os_drop_map_ref(struct
static void acpi_os_map_cleanup(struct acpi_ioremap *map)
{
if (!map->refcount) {
- synchronize_rcu_expedited();
+ if (acpi_sync_memory_unmap)
+ synchronize_rcu_expedited();
+
acpi_unmap(map->phys, map->virt);
kfree(map);
}
@@ -671,6 +674,8 @@ acpi_os_read_memory(acpi_physical_addres
bool unmap = false;
u64 dummy;

+ WARN_ON_ONCE(!acpi_sync_memory_unmap);
+
rcu_read_lock();
virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
if (!virt_addr) {
@@ -716,6 +721,8 @@ acpi_os_write_memory(acpi_physical_addre
unsigned int size = width / 8;
bool unmap = false;

+ WARN_ON_ONCE(!acpi_sync_memory_unmap);
+
rcu_read_lock();
virt_addr = acpi_map_vaddr_lookup(phys_addr, size);
if (!virt_addr) {
Index: linux-pm/include/acpi/acpi_io.h
===================================================================
--- linux-pm.orig/include/acpi/acpi_io.h
+++ linux-pm/include/acpi/acpi_io.h
@@ -14,6 +14,7 @@ static inline void __iomem *acpi_os_iore
#endif

extern bool acpi_permanent_mmap;
+extern bool acpi_sync_memory_unmap;

void __iomem *__ref
acpi_os_map_iomem(acpi_physical_address phys, acpi_size size);