linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Rafael J. Wysocki" <rjw@rjwysocki.net>
To: Dan Williams <dan.j.williams@intel.com>,
	Erik Kaneda <erik.kaneda@intel.com>
Cc: rafael.j.wysocki@intel.com, Len Brown <lenb@kernel.org>,
	Borislav Petkov <bp@alien8.de>, Ira Weiny <ira.weiny@intel.com>,
	James Morse <james.morse@arm.com>,
	Myron Stowe <myron.stowe@redhat.com>,
	Andy Shevchenko <andriy.shevchenko@linux.intel.com>,
	linux-kernel@vger.kernel.org, linux-acpi@vger.kernel.org,
	linux-nvdimm@lists.01.org, Bob Moore <robert.moore@intel.com>
Subject: [RFT][PATCH v2 2/4] ACPI: OSL: Add support for deferred unmapping of ACPI memory
Date: Mon, 22 Jun 2020 15:53:40 +0200	[thread overview]
Message-ID: <1821880.vZFEW4x2Ui@kreacher> (raw)
In-Reply-To: <2713141.s8EVnczdoM@kreacher>

From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>

Implement acpi_os_unmap_deferred() and
acpi_os_release_unused_mappings() and set ACPI_USE_DEFERRED_UNMAPPING
to allow ACPICA to use deferred unmapping of memory in
acpi_ex_system_memory_space_handler() so as to avoid RCU-related
performance issues with memory opregions.

Reported-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/acpi/osl.c                | 160 +++++++++++++++++++++++-------
 include/acpi/platform/aclinuxex.h |   4 +
 2 files changed, 128 insertions(+), 36 deletions(-)

diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 762c5d50b8fe..28863d908fa8 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -77,12 +77,16 @@ struct acpi_ioremap {
 	void __iomem *virt;
 	acpi_physical_address phys;
 	acpi_size size;
-	unsigned long refcount;
+	union {
+		unsigned long refcount;
+		struct list_head gc;
+	} track;
 };
 
 static LIST_HEAD(acpi_ioremaps);
 static DEFINE_MUTEX(acpi_ioremap_lock);
 #define acpi_ioremap_lock_held() lock_is_held(&acpi_ioremap_lock.dep_map)
+static LIST_HEAD(unused_mappings);
 
 static void __init acpi_request_region (struct acpi_generic_address *gas,
 	unsigned int length, char *desc)
@@ -250,7 +254,7 @@ void __iomem *acpi_os_get_iomem(acpi_physical_address phys, unsigned int size)
 	map = acpi_map_lookup(phys, size);
 	if (map) {
 		virt = map->virt + (phys - map->phys);
-		map->refcount++;
+		map->track.refcount++;
 	}
 	mutex_unlock(&acpi_ioremap_lock);
 	return virt;
@@ -335,7 +339,7 @@ void __iomem __ref
 	/* Check if there's a suitable mapping already. */
 	map = acpi_map_lookup(phys, size);
 	if (map) {
-		map->refcount++;
+		map->track.refcount++;
 		goto out;
 	}
 
@@ -358,7 +362,7 @@ void __iomem __ref
 	map->virt = virt;
 	map->phys = pg_off;
 	map->size = pg_sz;
-	map->refcount = 1;
+	map->track.refcount = 1;
 
 	list_add_tail_rcu(&map->list, &acpi_ioremaps);
 
@@ -375,40 +379,41 @@ void *__ref acpi_os_map_memory(acpi_physical_address phys, acpi_size size)
 EXPORT_SYMBOL_GPL(acpi_os_map_memory);
 
 /* Must be called with mutex_lock(&acpi_ioremap_lock) */
-static unsigned long acpi_os_drop_map_ref(struct acpi_ioremap *map)
+static bool acpi_os_drop_map_ref(struct acpi_ioremap *map, bool defer)
 {
-	unsigned long refcount = --map->refcount;
+	if (--map->track.refcount)
+		return true;
 
-	if (!refcount)
-		list_del_rcu(&map->list);
-	return refcount;
+	list_del_rcu(&map->list);
+
+	if (defer) {
+		INIT_LIST_HEAD(&map->track.gc);
+		list_add_tail(&map->track.gc, &unused_mappings);
+		return true;
+	}
+
+	return false;
 }
 
-static void acpi_os_map_cleanup(struct acpi_ioremap *map)
+static void __acpi_os_map_cleanup(struct acpi_ioremap *map)
 {
-	synchronize_rcu_expedited();
 	acpi_unmap(map->phys, map->virt);
 	kfree(map);
 }
 
-/**
- * acpi_os_unmap_iomem - Drop a memory mapping reference.
- * @virt: Start of the address range to drop a reference to.
- * @size: Size of the address range to drop a reference to.
- *
- * Look up the given virtual address range in the list of existing ACPI memory
- * mappings, drop a reference to it and unmap it if there are no more active
- * references to it.
- *
- * During early init (when acpi_permanent_mmap has not been set yet) this
- * routine simply calls __acpi_unmap_table() to get the job done.  Since
- * __acpi_unmap_table() is an __init function, the __ref annotation is needed
- * here.
- */
-void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size)
+static void acpi_os_map_cleanup(struct acpi_ioremap *map)
+{
+	if (!map)
+		return;
+
+	synchronize_rcu_expedited();
+	__acpi_os_map_cleanup(map);
+}
+
+static void __ref __acpi_os_unmap_iomem(void __iomem *virt, acpi_size size,
+					bool defer)
 {
 	struct acpi_ioremap *map;
-	unsigned long refcount;
 
 	if (!acpi_permanent_mmap) {
 		__acpi_unmap_table(virt, size);
@@ -416,26 +421,102 @@ void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size)
 	}
 
 	mutex_lock(&acpi_ioremap_lock);
+
 	map = acpi_map_lookup_virt(virt, size);
 	if (!map) {
 		mutex_unlock(&acpi_ioremap_lock);
 		WARN(true, PREFIX "%s: bad address %p\n", __func__, virt);
 		return;
 	}
-	refcount = acpi_os_drop_map_ref(map);
+	if (acpi_os_drop_map_ref(map, defer))
+		map = NULL;
+
 	mutex_unlock(&acpi_ioremap_lock);
 
-	if (!refcount)
-		acpi_os_map_cleanup(map);
+	acpi_os_map_cleanup(map);
+}
+
+/**
+ * acpi_os_unmap_iomem - Drop a memory mapping reference.
+ * @virt: Start of the address range to drop a reference to.
+ * @size: Size of the address range to drop a reference to.
+ *
+ * Look up the given virtual address range in the list of existing ACPI memory
+ * mappings, drop a reference to it and unmap it if there are no more active
+ * references to it.
+ *
+ * During early init (when acpi_permanent_mmap has not been set yet) this
+ * routine simply calls __acpi_unmap_table() to get the job done.  Since
+ * __acpi_unmap_table() is an __init function, the __ref annotation is needed
+ * here.
+ */
+void __ref acpi_os_unmap_iomem(void __iomem *virt, acpi_size size)
+{
+	__acpi_os_unmap_iomem(virt, size, false);
 }
 EXPORT_SYMBOL_GPL(acpi_os_unmap_iomem);
 
 void __ref acpi_os_unmap_memory(void *virt, acpi_size size)
 {
-	return acpi_os_unmap_iomem((void __iomem *)virt, size);
+	acpi_os_unmap_iomem((void __iomem *)virt, size);
 }
 EXPORT_SYMBOL_GPL(acpi_os_unmap_memory);
 
+/**
+ * acpi_os_unmap_deferred - Drop a memory mapping reference.
+ * @virt: Start of the address range to drop a reference to.
+ * @size: Size of the address range to drop a reference to.
+ *
+ * Look up the given virtual address range in the list of existing ACPI memory
+ * mappings, drop a reference to it and if there are no more active references
+ * to it, put it in the list of unused memory mappings.
+ *
+ * During early init (when acpi_permanent_mmap has not been set yet) this
+ * routine behaves like acpi_os_unmap_memory().
+ */
+void __ref acpi_os_unmap_deferred(void *virt, acpi_size size)
+{
+	__acpi_os_unmap_iomem((void __iomem *)virt, size, true);
+}
+
+/**
+ * acpi_os_release_unused_mappings - Release unused ACPI memory mappings.
+ */
+void acpi_os_release_unused_mappings(void)
+{
+	struct list_head list;
+
+	INIT_LIST_HEAD(&list);
+
+	/*
+	 * First avoid looking at mappings that may be added to the "unused"
+	 * list while the synchronize_rcu() below is running.
+	 */
+	mutex_lock(&acpi_ioremap_lock);
+
+	list_splice_init(&unused_mappings, &list);
+
+	mutex_unlock(&acpi_ioremap_lock);
+
+	if (list_empty(&list))
+		return;
+
+	/*
+	 * Wait for the possible users of the mappings in the "unused" list to
+	 * stop using them.
+	 */
+	synchronize_rcu();
+
+	/* Release the unused mappings in the list. */
+	while (!list_empty(&list)) {
+		struct acpi_ioremap *map;
+
+		map = list_entry(list.next, struct acpi_ioremap, track.gc);
+		list_del(&map->track.gc);
+		__acpi_os_map_cleanup(map);
+	}
+}
+
 int acpi_os_map_generic_address(struct acpi_generic_address *gas)
 {
 	u64 addr;
@@ -461,7 +542,6 @@ void acpi_os_unmap_generic_address(struct acpi_generic_address *gas)
 {
 	u64 addr;
 	struct acpi_ioremap *map;
-	unsigned long refcount;
 
 	if (gas->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
 		return;
@@ -472,16 +552,18 @@ void acpi_os_unmap_generic_address(struct acpi_generic_address *gas)
 		return;
 
 	mutex_lock(&acpi_ioremap_lock);
+
 	map = acpi_map_lookup(addr, gas->bit_width / 8);
 	if (!map) {
 		mutex_unlock(&acpi_ioremap_lock);
 		return;
 	}
-	refcount = acpi_os_drop_map_ref(map);
+	if (acpi_os_drop_map_ref(map, false))
+		map = NULL;
+
 	mutex_unlock(&acpi_ioremap_lock);
 
-	if (!refcount)
-		acpi_os_map_cleanup(map);
+	acpi_os_map_cleanup(map);
 }
 EXPORT_SYMBOL(acpi_os_unmap_generic_address);
 
@@ -1566,11 +1648,17 @@ static acpi_status acpi_deactivate_mem_region(acpi_handle handle, u32 level,
 acpi_status acpi_release_memory(acpi_handle handle, struct resource *res,
 				u32 level)
 {
+	acpi_status ret;
+
 	if (!(res->flags & IORESOURCE_MEM))
 		return AE_TYPE;
 
-	return acpi_walk_namespace(ACPI_TYPE_REGION, handle, level,
+	ret = acpi_walk_namespace(ACPI_TYPE_REGION, handle, level,
 				   acpi_deactivate_mem_region, NULL, res, NULL);
+
+	acpi_os_release_unused_mappings();
+
+	return ret;
 }
 EXPORT_SYMBOL_GPL(acpi_release_memory);
 
diff --git a/include/acpi/platform/aclinuxex.h b/include/acpi/platform/aclinuxex.h
index 04f88f2de781..e13f364d6c69 100644
--- a/include/acpi/platform/aclinuxex.h
+++ b/include/acpi/platform/aclinuxex.h
@@ -138,6 +138,10 @@ static inline void acpi_os_terminate_debugger(void)
 /*
  * OSL interfaces added by Linux
  */
+void acpi_os_unmap_deferred(void *virt, acpi_size size);
+void acpi_os_release_unused_mappings(void);
+
+#define ACPI_USE_DEFERRED_UNMAPPING
 
 #endif				/* __KERNEL__ */
 
-- 
2.26.2





  parent reply	other threads:[~2020-06-22 14:03 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-05-07 23:39 [PATCH v2] ACPI: Drop rcu usage for MMIO mappings Dan Williams
2020-05-13  8:52 ` [ACPI] 5a91d41f89: BUG:sleeping_function_called_from_invalid_context_at_kernel/locking/mutex.c kernel test robot
2020-06-05 13:32 ` [PATCH v2] ACPI: Drop rcu usage for MMIO mappings Rafael J. Wysocki
2020-06-05 16:18   ` Dan Williams
2020-06-05 16:21     ` Rafael J. Wysocki
2020-06-05 16:39       ` Dan Williams
2020-06-05 17:02         ` Rafael J. Wysocki
2020-06-05 14:06 ` [RFT][PATCH] ACPI: OSL: Use rwlock instead of RCU for memory management Rafael J. Wysocki
2020-06-05 17:08   ` Dan Williams
2020-06-06  6:56     ` Rafael J. Wysocki
2020-06-08 15:33       ` Rafael J. Wysocki
2020-06-08 16:29         ` Rafael J. Wysocki
2020-06-05 19:40   ` Andy Shevchenko
2020-06-06  6:48     ` Rafael J. Wysocki
2020-06-10 12:17 ` [RFT][PATCH 0/3] ACPI: ACPICA / OSL: Avoid unmapping ACPI memory inside of the AML interpreter Rafael J. Wysocki
2020-06-10 12:20   ` [RFT][PATCH 1/3] ACPICA: Defer unmapping of memory used in memory opregions Rafael J. Wysocki
2020-06-10 12:21   ` [RFT][PATCH 2/3] ACPICA: Remove unused memory mappings on interpreter exit Rafael J. Wysocki
2020-06-12  0:12     ` Kaneda, Erik
2020-06-12 12:05       ` Rafael J. Wysocki
2020-06-13 19:28         ` Rafael J. Wysocki
2020-06-15 19:06           ` Dan Williams
2020-06-10 12:22   ` [RFT][PATCH 3/3] ACPI: OSL: Define ACPI_OS_MAP_MEMORY_FAST_PATH() Rafael J. Wysocki
2020-06-13 19:19   ` [RFT][PATCH 0/3] ACPI: ACPICA / OSL: Avoid unmapping ACPI memory inside of the AML interpreter Rafael J. Wysocki
2020-06-22 13:50 ` [RFT][PATCH v2 0/4] " Rafael J. Wysocki
2020-06-22 13:52   ` [RFT][PATCH v2 1/4] ACPICA: Defer unmapping of opregion memory if supported by OS Rafael J. Wysocki
2020-06-22 13:53   ` Rafael J. Wysocki [this message]
2020-06-22 14:56     ` [RFT][PATCH v2 2/4] ACPI: OSL: Add support for deferred unmapping of ACPI memory Andy Shevchenko
2020-06-22 15:27       ` Rafael J. Wysocki
2020-06-22 15:46         ` Andy Shevchenko
2020-06-22 14:01   ` [RFT][PATCH v2 3/4] ACPICA: Preserve memory opregion mappings if supported by OS Rafael J. Wysocki
2020-06-26 22:53     ` Kaneda, Erik
2020-06-29 13:02       ` Rafael J. Wysocki
2020-06-22 14:02   ` [RFT][PATCH v2 4/4] ACPI: OSL: Implement acpi_os_map_memory_fast_path() Rafael J. Wysocki
2020-06-26 17:28   ` [RFT][PATCH v3 0/4] ACPI: ACPICA / OSL: Avoid unmapping ACPI memory inside of the AML interpreter Rafael J. Wysocki
2020-06-26 17:31     ` [RFT][PATCH v3 1/4] ACPICA: Take deferred unmapping of memory into account Rafael J. Wysocki
2020-06-26 17:31     ` [RFT][PATCH v3 2/4] ACPI: OSL: Implement deferred unmapping of ACPI memory Rafael J. Wysocki
2020-06-26 17:32     ` [RFT][PATCH v3 3/4] ACPICA: Preserve memory opregion mappings if supported by OS Rafael J. Wysocki
2020-06-26 17:33     ` [RFT][PATCH v3 4/4] ACPI: OSL: Implement acpi_os_map_memory_fast_path() Rafael J. Wysocki
2020-06-26 18:41     ` [RFT][PATCH v3 0/4] ACPI: ACPICA / OSL: Avoid unmapping ACPI memory inside of the AML interpreter Dan Williams
2020-06-28 17:09       ` Rafael J. Wysocki
2020-06-29 20:46         ` Dan Williams
2020-06-30 11:04           ` Rafael J. Wysocki
2020-06-29 16:31     ` [PATCH v4 0/2] " Rafael J. Wysocki
2020-06-29 16:33       ` [PATCH v4 1/2] ACPI: OSL: Implement deferred unmapping of ACPI memory Rafael J. Wysocki
2020-06-29 16:33       ` [PATCH v4 2/2] ACPICA: Preserve memory opregion mappings Rafael J. Wysocki
2020-06-29 20:57         ` Al Stone
2020-06-30 11:44           ` Rafael J. Wysocki
2020-06-30 15:31             ` Al Stone
2020-06-30 15:52               ` Rafael J. Wysocki
2020-06-30 19:57                 ` Al Stone
2020-07-16 19:22         ` Verma, Vishal L
2020-07-19 19:14           ` Rafael J. Wysocki

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1821880.vZFEW4x2Ui@kreacher \
    --to=rjw@rjwysocki.net \
    --cc=andriy.shevchenko@linux.intel.com \
    --cc=bp@alien8.de \
    --cc=dan.j.williams@intel.com \
    --cc=erik.kaneda@intel.com \
    --cc=ira.weiny@intel.com \
    --cc=james.morse@arm.com \
    --cc=lenb@kernel.org \
    --cc=linux-acpi@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-nvdimm@lists.01.org \
    --cc=myron.stowe@redhat.com \
    --cc=rafael.j.wysocki@intel.com \
    --cc=robert.moore@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).