Skip to content

Commit 067353a

Browse files
davejiangdjbw
authored andcommitted
cxl/region: Add memory hotplug notifier for cxl region
When the CXL region is formed, the driver computes the performance data for the region. However this data is not available at the node data collection that has been populated by the HMAT during kernel initialization. Add a memory hotplug notifier to update the access coordinates to the 'struct memory_target' context kept by the HMAT_REPORTING code. Add CXL_CALLBACK_PRI for a memory hotplug callback priority. Set the priority number to be called before HMAT_CALLBACK_PRI. The CXL update must happen before hmat_callback(). A new HMAT_REPORTING helper hmat_update_target_coordinates() is added in order to allow CXL to update the memory_target access coordinates. A new ext_updated member is added to the memory_target to indicate that the access coordinates within the memory_target has been updated by an external agent such as CXL. This prevents data being overwritten by the hmat_update_target_attrs() triggered by hmat_callback(). Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Rafael J. Wysocki <rafael@kernel.org> Reviewed-by: Huang, Ying <ying.huang@intel.com> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Tested-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Signed-off-by: Dave Jiang <dave.jiang@intel.com> Link: https://lore.kernel.org/r/20240308220055.2172956-12-dave.jiang@intel.com Signed-off-by: Dan Williams <dan.j.williams@intel.com>
1 parent c20eaf4 commit 067353a

File tree

7 files changed

+127
-0
lines changed

7 files changed

+127
-0
lines changed

drivers/acpi/numa/hmat.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ struct memory_target {
7474
struct node_cache_attrs cache_attrs;
7575
u8 gen_port_device_handle[ACPI_SRAT_DEVICE_HANDLE_SIZE];
7676
bool registered;
77+
bool ext_updated; /* externally updated */
7778
};
7879

7980
struct memory_initiator {
@@ -328,6 +329,35 @@ static void hmat_update_target_access(struct memory_target *target,
328329
}
329330
}
330331

332+
int hmat_update_target_coordinates(int nid, struct access_coordinate *coord,
333+
enum access_coordinate_class access)
334+
{
335+
struct memory_target *target;
336+
int pxm;
337+
338+
if (nid == NUMA_NO_NODE)
339+
return -EINVAL;
340+
341+
pxm = node_to_pxm(nid);
342+
guard(mutex)(&target_lock);
343+
target = find_mem_target(pxm);
344+
if (!target)
345+
return -ENODEV;
346+
347+
hmat_update_target_access(target, ACPI_HMAT_READ_LATENCY,
348+
coord->read_latency, access);
349+
hmat_update_target_access(target, ACPI_HMAT_WRITE_LATENCY,
350+
coord->write_latency, access);
351+
hmat_update_target_access(target, ACPI_HMAT_READ_BANDWIDTH,
352+
coord->read_bandwidth, access);
353+
hmat_update_target_access(target, ACPI_HMAT_WRITE_BANDWIDTH,
354+
coord->write_bandwidth, access);
355+
target->ext_updated = true;
356+
357+
return 0;
358+
}
359+
EXPORT_SYMBOL_GPL(hmat_update_target_coordinates);
360+
331361
static __init void hmat_add_locality(struct acpi_hmat_locality *hmat_loc)
332362
{
333363
struct memory_locality *loc;
@@ -699,6 +729,10 @@ static void hmat_update_target_attrs(struct memory_target *target,
699729
u32 best = 0;
700730
int i;
701731

732+
/* Don't update if an external agent has changed the data. */
733+
if (target->ext_updated)
734+
return;
735+
702736
/* Don't update for generic port if there's no device handle */
703737
if ((access == NODE_ACCESS_CLASS_GENPORT_SINK_LOCAL ||
704738
access == NODE_ACCESS_CLASS_GENPORT_SINK_CPU) &&

drivers/cxl/core/cdat.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,3 +580,9 @@ void cxl_region_perf_data_calculate(struct cxl_region *cxlr,
580580
DIV_ROUND_UP(cxlr->coord[i].write_latency, 1000);
581581
}
582582
}
583+
584+
int cxl_update_hmat_access_coordinates(int nid, struct cxl_region *cxlr,
585+
enum access_coordinate_class access)
586+
{
587+
return hmat_update_target_coordinates(nid, &cxlr->coord[access], access);
588+
}

drivers/cxl/core/core.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,4 +90,7 @@ enum cxl_poison_trace_type {
9090

9191
long cxl_pci_get_latency(struct pci_dev *pdev);
9292

93+
int cxl_update_hmat_access_coordinates(int nid, struct cxl_region *cxlr,
94+
enum access_coordinate_class access);
95+
9396
#endif /* __CXL_CORE_H__ */

drivers/cxl/core/region.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#include <linux/genalloc.h>
55
#include <linux/device.h>
66
#include <linux/module.h>
7+
#include <linux/memory.h>
78
#include <linux/slab.h>
89
#include <linux/uuid.h>
910
#include <linux/sort.h>
@@ -116,12 +117,22 @@ static const struct attribute_group cxl_region_access0_coordinate_group = {
116117
.is_visible = cxl_region_access0_coordinate_visible,
117118
};
118119

120+
static const struct attribute_group *get_cxl_region_access0_group(void)
121+
{
122+
return &cxl_region_access0_coordinate_group;
123+
}
124+
119125
static const struct attribute_group cxl_region_access1_coordinate_group = {
120126
.name = "access1",
121127
.attrs = access1_coordinate_attrs,
122128
.is_visible = cxl_region_access1_coordinate_visible,
123129
};
124130

131+
static const struct attribute_group *get_cxl_region_access1_group(void)
132+
{
133+
return &cxl_region_access1_coordinate_group;
134+
}
135+
125136
static ssize_t uuid_show(struct device *dev, struct device_attribute *attr,
126137
char *buf)
127138
{
@@ -2216,6 +2227,7 @@ static void unregister_region(void *_cxlr)
22162227
struct cxl_region_params *p = &cxlr->params;
22172228
int i;
22182229

2230+
unregister_memory_notifier(&cxlr->memory_notifier);
22192231
device_del(&cxlr->dev);
22202232

22212233
/*
@@ -2260,6 +2272,58 @@ static struct cxl_region *cxl_region_alloc(struct cxl_root_decoder *cxlrd, int i
22602272
return cxlr;
22612273
}
22622274

2275+
static bool cxl_region_update_coordinates(struct cxl_region *cxlr, int nid)
2276+
{
2277+
int cset = 0;
2278+
int rc;
2279+
2280+
for (int i = 0; i < ACCESS_COORDINATE_MAX; i++) {
2281+
if (cxlr->coord[i].read_bandwidth) {
2282+
rc = cxl_update_hmat_access_coordinates(nid, cxlr, i);
2283+
if (rc == 0)
2284+
cset++;
2285+
}
2286+
}
2287+
2288+
if (!cset)
2289+
return false;
2290+
2291+
rc = sysfs_update_group(&cxlr->dev.kobj, get_cxl_region_access0_group());
2292+
if (rc)
2293+
dev_dbg(&cxlr->dev, "Failed to update access0 group\n");
2294+
2295+
rc = sysfs_update_group(&cxlr->dev.kobj, get_cxl_region_access1_group());
2296+
if (rc)
2297+
dev_dbg(&cxlr->dev, "Failed to update access1 group\n");
2298+
2299+
return true;
2300+
}
2301+
2302+
static int cxl_region_perf_attrs_callback(struct notifier_block *nb,
2303+
unsigned long action, void *arg)
2304+
{
2305+
struct cxl_region *cxlr = container_of(nb, struct cxl_region,
2306+
memory_notifier);
2307+
struct cxl_region_params *p = &cxlr->params;
2308+
struct cxl_endpoint_decoder *cxled = p->targets[0];
2309+
struct cxl_decoder *cxld = &cxled->cxld;
2310+
struct memory_notify *mnb = arg;
2311+
int nid = mnb->status_change_nid;
2312+
int region_nid;
2313+
2314+
if (nid == NUMA_NO_NODE || action != MEM_ONLINE)
2315+
return NOTIFY_DONE;
2316+
2317+
region_nid = phys_to_target_node(cxld->hpa_range.start);
2318+
if (nid != region_nid)
2319+
return NOTIFY_DONE;
2320+
2321+
if (!cxl_region_update_coordinates(cxlr, nid))
2322+
return NOTIFY_DONE;
2323+
2324+
return NOTIFY_OK;
2325+
}
2326+
22632327
/**
22642328
* devm_cxl_add_region - Adds a region to a decoder
22652329
* @cxlrd: root decoder
@@ -2307,6 +2371,10 @@ static struct cxl_region *devm_cxl_add_region(struct cxl_root_decoder *cxlrd,
23072371
if (rc)
23082372
goto err;
23092373

2374+
cxlr->memory_notifier.notifier_call = cxl_region_perf_attrs_callback;
2375+
cxlr->memory_notifier.priority = CXL_CALLBACK_PRI;
2376+
register_memory_notifier(&cxlr->memory_notifier);
2377+
23102378
rc = devm_add_action_or_reset(port->uport_dev, unregister_region, cxlr);
23112379
if (rc)
23122380
return ERR_PTR(rc);

drivers/cxl/cxl.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <linux/libnvdimm.h>
88
#include <linux/bitfield.h>
9+
#include <linux/notifier.h>
910
#include <linux/bitops.h>
1011
#include <linux/log2.h>
1112
#include <linux/node.h>
@@ -518,6 +519,7 @@ struct cxl_region_params {
518519
* @flags: Region state flags
519520
* @params: active + config params for the region
520521
* @coord: QoS access coordinates for the region
522+
* @memory_notifier: notifier for setting the access coordinates to node
521523
*/
522524
struct cxl_region {
523525
struct device dev;
@@ -529,6 +531,7 @@ struct cxl_region {
529531
unsigned long flags;
530532
struct cxl_region_params params;
531533
struct access_coordinate coord[ACCESS_COORDINATE_MAX];
534+
struct notifier_block memory_notifier;
532535
};
533536

534537
struct cxl_nvdimm_bridge {

include/linux/acpi.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1547,4 +1547,16 @@ static inline void acpi_use_parent_companion(struct device *dev)
15471547
ACPI_COMPANION_SET(dev, ACPI_COMPANION(dev->parent));
15481548
}
15491549

1550+
#ifdef CONFIG_ACPI_HMAT
1551+
int hmat_update_target_coordinates(int nid, struct access_coordinate *coord,
1552+
enum access_coordinate_class access);
1553+
#else
1554+
static inline int hmat_update_target_coordinates(int nid,
1555+
struct access_coordinate *coord,
1556+
enum access_coordinate_class access)
1557+
{
1558+
return -EOPNOTSUPP;
1559+
}
1560+
#endif
1561+
15501562
#endif /*_LINUX_ACPI_H*/

include/linux/memory.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ struct mem_section;
114114
#define DEFAULT_CALLBACK_PRI 0
115115
#define SLAB_CALLBACK_PRI 1
116116
#define HMAT_CALLBACK_PRI 2
117+
#define CXL_CALLBACK_PRI 5
117118
#define MM_COMPUTE_BATCH_PRI 10
118119
#define CPUSET_CALLBACK_PRI 10
119120
#define MEMTIER_HOTPLUG_PRI 100

0 commit comments

Comments
 (0)