@@ -60,6 +60,7 @@ config CXL_ACPI
default CXL_BUS
select ACPI_TABLE_LIB
select ACPI_HMAT
+ select SOFT_RESERVED_MANAGED
help
Enable support for host managed device memory (HDM) resources
published by a platform's ACPI CXL memory layout description. See
@@ -7,6 +7,8 @@
#include <linux/acpi.h>
#include <linux/pci.h>
#include <linux/node.h>
+#include <linux/pm.h>
+#include <linux/workqueue.h>
#include <asm/div64.h>
#include "cxlpci.h"
#include "cxl.h"
@@ -813,6 +815,27 @@ static int pair_cxl_resource(struct device *dev, void *data)
return 0;
}
+static void cxl_srmem_work_fn(struct work_struct *work)
+{
+ /* Wait for CXL PCI and mem drivers to load */
+ cxl_wait_for_pci_mem();
+
+ /*
+ * Once the CXL PCI and mem drivers have loaded wait
+ * for the driver probe routines to complete.
+ */
+ wait_for_device_probe();
+
+ cxl_region_srmem_update();
+}
+
+DECLARE_WORK(cxl_sr_work, cxl_srmem_work_fn);
+
+static void cxl_srmem_update(void)
+{
+ schedule_work(&cxl_sr_work);
+}
+
static int cxl_acpi_probe(struct platform_device *pdev)
{
int rc;
@@ -887,6 +910,9 @@ static int cxl_acpi_probe(struct platform_device *pdev)
/* In case PCI is scanned before ACPI re-trigger memdev attach */
cxl_bus_rescan();
+
+ /* Update SOFT RESERVED resources that intersect with CXL regions */
+ cxl_srmem_update();
return 0;
}
@@ -1,6 +1,6 @@
# SPDX-License-Identifier: GPL-2.0
obj-$(CONFIG_CXL_BUS) += cxl_core.o
-obj-$(CONFIG_CXL_SUSPEND) += suspend.o
+obj-y += suspend.o
ccflags-y += -I$(srctree)/drivers/cxl
CFLAGS_trace.o = -DTRACE_INCLUDE_PATH=. -I$(src)
@@ -10,6 +10,7 @@
#include <linux/sort.h>
#include <linux/idr.h>
#include <linux/memory-tiers.h>
+#include <linux/ioport.h>
#include <cxlmem.h>
#include <cxl.h>
#include "core.h"
@@ -2294,7 +2295,7 @@ const struct device_type cxl_region_type = {
bool is_cxl_region(struct device *dev)
{
- return dev->type == &cxl_region_type;
+ return dev && dev->type == &cxl_region_type;
}
EXPORT_SYMBOL_NS_GPL(is_cxl_region, CXL);
@@ -3377,6 +3378,28 @@ int cxl_add_to_region(struct cxl_port *root, struct cxl_endpoint_decoder *cxled)
}
EXPORT_SYMBOL_NS_GPL(cxl_add_to_region, CXL);
+int cxl_region_srmem_update(void)
+{
+ struct device *dev = NULL;
+ struct cxl_region *cxlr;
+ struct resource *res;
+
+ do {
+ dev = bus_find_next_device(&cxl_bus_type, dev);
+ if (is_cxl_region(dev)) {
+ cxlr = to_cxl_region(dev);
+ res = cxlr->params.res;
+ release_srmem_region_adjustable(res->start,
+ resource_size(res));
+ put_device(dev);
+ }
+ } while (dev);
+
+ merge_srmem_resources();
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_region_srmem_update, CXL);
+
static int is_system_ram(struct resource *res, void *arg)
{
struct cxl_region *cxlr = arg;
@@ -2,18 +2,27 @@
/* Copyright(c) 2022 Intel Corporation. All rights reserved. */
#include <linux/atomic.h>
#include <linux/export.h>
+#include <linux/wait.h>
#include "cxlmem.h"
+#include "cxlpci.h"
static atomic_t mem_active;
+static DECLARE_WAIT_QUEUE_HEAD(cxl_wait_queue);
+
+static atomic_t pci_loaded;
+
+#ifdef CONFIG_CXL_SUSPEND
bool cxl_mem_active(void)
{
return atomic_read(&mem_active) != 0;
}
+#endif
void cxl_mem_active_inc(void)
{
atomic_inc(&mem_active);
+ wake_up(&cxl_wait_queue);
}
EXPORT_SYMBOL_NS_GPL(cxl_mem_active_inc, CXL);
@@ -22,3 +31,35 @@ void cxl_mem_active_dec(void)
atomic_dec(&mem_active);
}
EXPORT_SYMBOL_NS_GPL(cxl_mem_active_dec, CXL);
+
+void mark_cxl_pci_loaded(void)
+{
+ atomic_inc(&pci_loaded);
+ wake_up(&cxl_wait_queue);
+}
+EXPORT_SYMBOL_NS_GPL(mark_cxl_pci_loaded, CXL);
+
+static bool cxl_pci_loaded(void)
+{
+ if (IS_ENABLED(CONFIG_CXL_PCI))
+ return atomic_read(&pci_loaded) != 0;
+
+ return true;
+}
+
+static bool cxl_mem_probed(void)
+{
+ if (IS_ENABLED(CONFIG_CXL_MEM))
+ return atomic_read(&mem_active) != 0;
+
+ return true;
+}
+
+void cxl_wait_for_pci_mem(void)
+{
+ if (IS_ENABLED(CONFIG_CXL_PCI) || IS_ENABLED(CONFIG_CXL_MEM))
+ wait_event_timeout(cxl_wait_queue,
+ cxl_pci_loaded() && cxl_mem_probed(),
+ 30 * HZ);
+}
+EXPORT_SYMBOL_NS_GPL(cxl_wait_for_pci_mem, CXL);
@@ -861,6 +861,7 @@ bool is_cxl_pmem_region(struct device *dev);
struct cxl_pmem_region *to_cxl_pmem_region(struct device *dev);
int cxl_add_to_region(struct cxl_port *root,
struct cxl_endpoint_decoder *cxled);
+int cxl_region_srmem_update(void);
struct cxl_dax_region *to_cxl_dax_region(struct device *dev);
#else
static inline bool is_cxl_pmem_region(struct device *dev)
@@ -898,6 +899,8 @@ void cxl_coordinates_combine(struct access_coordinate *out,
bool cxl_endpoint_decoder_reset_detected(struct cxl_port *port);
+void cxl_wait_for_pci_mem(void);
+
/*
* Unit test builds overrides this to __weak, find the 'strong' version
* of these symbols in tools/testing/cxl/.
@@ -838,17 +838,8 @@ int cxl_trigger_poison_list(struct cxl_memdev *cxlmd);
int cxl_inject_poison(struct cxl_memdev *cxlmd, u64 dpa);
int cxl_clear_poison(struct cxl_memdev *cxlmd, u64 dpa);
-#ifdef CONFIG_CXL_SUSPEND
void cxl_mem_active_inc(void);
void cxl_mem_active_dec(void);
-#else
-static inline void cxl_mem_active_inc(void)
-{
-}
-static inline void cxl_mem_active_dec(void)
-{
-}
-#endif
int cxl_mem_sanitize(struct cxl_memdev *cxlmd, u16 cmd);
@@ -129,4 +129,6 @@ void read_cdat_data(struct cxl_port *port);
void cxl_cor_error_detected(struct pci_dev *pdev);
pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
pci_channel_state_t state);
+
+void mark_cxl_pci_loaded(void);
#endif /* __CXL_PCI_H__ */
@@ -1054,6 +1054,7 @@ static int __init cxl_pci_driver_init(void)
if (rc)
pci_unregister_driver(&cxl_pci_driver);
+ mark_cxl_pci_loaded();
return rc;
}
Update handling of SOFT RESERVE iomem resources that intersect with CXL region resources to remove intersections from the SOFT RESERVE resources. The current approach of leaving SOFT RESERVE resources as is can cause failures during hotplug replace of CXL devices bercause the resource is not avaialable for reuse after teardown of the CXL device. The approach is to use the CONFIG_SOFT_RESERVED_MANAGED config option to have SOFT RESERVE resources set aside during boot. After the CXL drivers complete their probe and CXL regions are created any CXL region intersections with SOFT RESERVE resources are removed from the SOFT RESERVE resource. The remaining SOFT RESERVE resources, if any, are then added to the iomem resource tree. To accomplish this the cxl acpi driver creates a worker thread at the end of cxl_acpi_probe(). This worker thread first waits for the CXL PCI CXL mem drivers have loaded. The cxl core/suspend.c code is updated to add a pci_loaded variable, in addition to the mem_active variable, that is updated when the pci driver loads. A new cxl_wait_for_pci_mem() routine uses a waitqueue for both these driver to be loaded. The need to add this additional waitqueue is ensure the CXL PCI and CXL mem drivers have loaded before we wait for their probe, without it the cxl acpi probe worker thread calls wait_for_device_probe() before these drivers are loaded. After the CXL PCI and CXL mem drivers load the cxl acpi worker thread uses wait_for_device_probe() to ensure device probe routines have completed. After probe completes, find all cxl regions that have been created and remove any intersections with SOFT RESERVE resources and add remaining SOFT RESERRVES to the iomem resource tree. Signed-off-by: Nathan Fontenot <nathan.fontenot@amd.com> --- drivers/cxl/Kconfig | 1 + drivers/cxl/acpi.c | 26 ++++++++++++++++++++++++ drivers/cxl/core/Makefile | 2 +- drivers/cxl/core/region.c | 25 ++++++++++++++++++++++- drivers/cxl/core/suspend.c | 41 ++++++++++++++++++++++++++++++++++++++ drivers/cxl/cxl.h | 3 +++ drivers/cxl/cxlmem.h | 9 --------- drivers/cxl/cxlpci.h | 2 ++ drivers/cxl/pci.c | 1 + 9 files changed, 99 insertions(+), 11 deletions(-)