cxl: Add support to report region access coordinates to numa nodes
Subsystems (4)
Dave Jiang
maintainerv7 cover cxl: Add support to report region access coordinates to numa nodes
Hi Rafael,
Please review patches 1-4,10,11 and ack if they look ok to you. Thank you!
Hi Greg,
Please review patch 11 and ack the numa node bits if they look ok to you. Thank you!
v7:
- Add review tag from Greg
- Add review and test tags from Jonathan
- Fix typos (Jonathan)
- Move memory_notifier registeration to devm_cxl_add_region() (Dan)
v6:
- Enhance macros used to reduce code for cxl access coordinates sysfs attrs (Jonathan)
- Various minor updates and fixes, see per commit details. (Jonathan)
- Added review tags from Jonathan.
v5:
- Fix various 0-day issues
- Remove EXPORT_SYMBOL for cxl_coords_combine() (Dan)
- Rebased against fixes series for qos_class
https://lore.kernel.org/linux-cxl/[email protected]/T/#t
v4:
- Introduce access class 0 and 1 for CXL access coordinates.
- See individual patches for detailed change log if applicable.
v3:
- Make attributes not visible if no data. (Jonathan)
- Fix documentation verbiage. (Jonathan)
- Check against read bandwidth instead of write bandwidth due to future RO devices. (Jonathan)
- Export node_set_perf_attrs() to all namespaces. (Jonathan)
- Remove setting of coordinate access level 1. (Jonathan)
v2:
- Move calculation function to core/cdat.c due to QTG series changes
- Make cxlr->coord static (Dan)
- Move calculation to cxl_region_attach to be under cxl_dpa_rwsem (Dan)
- Normalize perf latency numbers to nanoseconds (Brice)
- Update documentation with units and initiator details (Brice, Dan)
- Fix notifier return values (Dan)
- Use devm_add_action_or_reset() to unregister memory notifier (Dan)
This series adds support for computing the performance data of a CXL region and also updates the performance data to the NUMA node. This series depends on the CXL QOS class series that's pending 6.8 pull request.
CXL memory devices already attached before boot are enumerated by the BIOS. The SRAT and HMAT tables are properly setup to including memory regions enumerated from those CXL memory devices. For regions not programmed or a hot-plugged CXL memory device, the BIOS does not have the relevant information and the performance data has to be caluclated by the driver post region assembly.
According to numaperf documentation [1] there are 2 access classes defined for performance between an initiator node and a memory target node. Access class "0" describes attributes between a memory target and the highest performing initator local to the target. In this case the initiator can be a CPU or an I/O initiator such as a GPU or NIC. Access class "1" describes attributes between a memory target and the nearest CPU node. Both access classes are calculated for the CXL memory target and updated for NUMA nodes through HMAT_REPORTING code or directly depending on if the NUMA node is described by the ACPI SRAT table.
Recall from qos_class series (v6.8) that the performance data for the ranges of a CXL memory device is computed and cached. A CXL memory region can be backed by one or more devices. Thus the performance data would be the aggregated bandwidth of all devices that back a region and the worst latency out of all devices backing the region.
See kernel git branch [2] for convenience.
[1]: https://www.kernel.org/doc/Documentation/admin-guide/mm/numaperf.rst
[2]: https://git.kernel.org/pub/scm/linux/kernel/git/djiang/linux.git/log/?h=cxl-hmem-report
Dave Jiang
maintainerPATCH v7 1/12 ACPI: HMAT: Remove register of memory node for generic target
For generic targets, there's no reason to call register_memory_node_under_compute_node() with the access levels that are only visible to HMAT handling code. Only update the attributes and rename hmat_register_generic_target_initiators() to hmat_update_generic_target().
The original call path ends up triggering register_memory_node_under_compute_node(). Although the access level would be "3" and not impact any current node arrays, it introduces unwanted data into the numa node access_coordinate array.
--- drivers/acpi/numa/hmat.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/acpi/numa/hmat.c +4 -4
@@ -770,12 +770,12 @@ static void __hmat_register_target_initiators(struct memory_target *target, } } -static void hmat_register_generic_target_initiators (struct memory_target *target) +static void hmat_update_generic_target (struct memory_target *target) { static DECLARE_BITMAP(p_nodes, MAX_NUMNODES); -__hmat_register_target_initiators (target, p_nodes, - NODE_ACCESS_CLASS_GENPORT_SINK); +hmat_update_target_attrs (target, p_nodes, + NODE_ACCESS_CLASS_GENPORT_SINK); }static void hmat_register_target_initiators (struct memory_target *target)
@@ -835,7 +835,7 @@ static void hmat_register_target(struct memory_target *target)*/ mutex_lock (&target_lock);if (*(u16 *)target->gen_port_device_handle) { -hmat_register_generic_target_initiators (target); +hmat_update_generic_target (target); target->registered = true; }mutex_unlock (&target_lock);
Signature · 1 line
2.44.0
Dave Jiang
maintainerPATCH v7 2/12 base/node / ACPI: Enumerate node access class for 'struct access_coordinate'
In reply to Dave JiangBoth generic node and HMAT handling code have been using magic numbers to indicate access classes for 'struct access_coordinate'. Introduce enums to enumerate the access0 and access1 classes shared by the two subsystems. Update the function parameters and callers as appropriate to utilize the new enum.
Access0 is named to ACCESS_COORDINATE_LOCAL in order to indicate that the access class is for 'struct access_coordinate' between a target node and the nearest initiator node.
Access1 is named to ACCESS_COORDINATE_CPU in order to indicate that the access class is for 'struct access_coordinate' between a target node and the nearest CPU node.
--- drivers/acpi/numa/hmat.c | 26 ++++++++++++++------------ drivers/base/node.c | 6 +++--- include/linux/node.h | 18 +++++++++++++++--- 3 files changed, 32 insertions(+), 18 deletions(-)
drivers/acpi/numa/hmat.c +14 -12
@@ -59,9 +59,7 @@ struct target_cache { };enum { -NODE_ACCESS_CLASS_0 =0 , -NODE_ACCESS_CLASS_1 , -NODE_ACCESS_CLASS_GENPORT_SINK , +NODE_ACCESS_CLASS_GENPORT_SINK =ACCESS_COORDINATE_MAX ,NODE_ACCESS_CLASS_MAX , };
@@ -374,11 +372,11 @@ static __init void hmat_update_target(unsigned int tgt_pxm, unsigned int init_pxif (target && target->processor_pxm == init_pxm) {hmat_update_target_access (target, type, value, -NODE_ACCESS_CLASS_0 ); +ACCESS_COORDINATE_LOCAL );/* If the node has a CPU, update access 1 */ if (node_state (pxm_to_node (init_pxm),N_CPU ))hmat_update_target_access (target, type, value, -NODE_ACCESS_CLASS_1 ); +ACCESS_COORDINATE_CPU ); } }
@@ -709,7 +707,8 @@ static void hmat_update_target_attrs(struct memory_target *target,*/ if (target->processor_pxm !=PXM_INVAL ) { cpu_nid =pxm_to_node (target->processor_pxm); -if (access ==0 ||node_state (cpu_nid,N_CPU )) { +if (access ==ACCESS_COORDINATE_LOCAL || +node_state (cpu_nid,N_CPU )) {set_bit (target->processor_pxm, p_nodes);return ; }
@@ -737,7 +736,8 @@ static void hmat_update_target_attrs(struct memory_target *target,list_for_each_entry (initiator, &initiators, node) {u32 value; -if (access ==1 && !initiator->has_cpu) { +if (access ==ACCESS_COORDINATE_CPU && + !initiator->has_cpu) {clear_bit (initiator->processor_pxm, p_nodes);continue ; }
@@ -782,8 +782,10 @@ static void hmat_register_target_initiators(struct memory_target *target) { static DECLARE_BITMAP(p_nodes, MAX_NUMNODES); -__hmat_register_target_initiators (target, p_nodes,0 ); -__hmat_register_target_initiators (target, p_nodes,1 ); +__hmat_register_target_initiators (target, p_nodes, + ACCESS_COORDINATE_LOCAL); +__hmat_register_target_initiators (target, p_nodes, +ACCESS_COORDINATE_CPU ); }static void hmat_register_target_cache (struct memory_target *target)
@@ -854,8 +856,8 @@ static void hmat_register_target(struct memory_target *target)if (!target->registered) {hmat_register_target_initiators (target);hmat_register_target_cache (target); -hmat_register_target_perf (target,NODE_ACCESS_CLASS_0 ); -hmat_register_target_perf (target,NODE_ACCESS_CLASS_1 ); +hmat_register_target_perf (target,ACCESS_COORDINATE_LOCAL ); +hmat_register_target_perf (target,ACCESS_COORDINATE_CPU ); target->registered = true; }mutex_unlock (&target_lock);
@@ -927,7 +929,7 @@ static int hmat_calculate_adistance(struct notifier_block *self,return NOTIFY_OK ;mutex_lock (&target_lock); -hmat_update_target_attrs (target, p_nodes,1 ); +hmat_update_target_attrs (target, p_nodes,ACCESS_COORDINATE_CPU );mutex_unlock (&target_lock); perf = &target->coord[1 ];
drivers/base/node.c +3 -3
@@ -126,7 +126,7 @@ static void node_access_release(struct device *dev) }static struct node_access_nodes *node_init_node_access (struct node *node, -unsigned int access) +enum access_coordinate_class access) {struct node_access_nodes *access_node;struct device *dev;
@@ -191,7 +191,7 @@ static struct attribute *access_attrs[] = {* @access: The access class the for the given attributes */ void node_set_perf_attrs (unsigned int nid,struct access_coordinate *coord, -unsigned int access) +enum access_coordinate_class access) {struct node_access_nodes *c;struct node *node;
@@ -689,7 +689,7 @@ int register_cpu_under_node(unsigned int cpu, unsigned int nid)*/ int register_memory_node_under_compute_node (unsigned int mem_nid,unsigned int cpu_nid, -unsigned int access) +enum access_coordinate_class access) {struct node *init_node, *targ_node;struct node_access_nodes *initiator, *target;
include/linux/node.h +15 -3
@@ -34,6 +34,18 @@ struct access_coordinate {unsigned int write_latency; }; +/* +* ACCESS_COORDINATE_LOCAL correlates to ACCESS CLASS 0 +* - access_coordinate between target node and nearest initiator node +* ACCESS_COORDINATE_CPU correlates to ACCESS CLASS 1 +* - access_coordinate between target node and nearest CPU node +*/ +enum access_coordinate_class { +ACCESS_COORDINATE_LOCAL , +ACCESS_COORDINATE_CPU , +ACCESS_COORDINATE_MAX +}; +enum cache_indexing {NODE_CACHE_DIRECT_MAP ,NODE_CACHE_INDEXED ,
@@ -66,7 +78,7 @@ struct node_cache_attrs {#ifdef CONFIG_HMEM_REPORTING void node_add_cache (unsigned int nid,struct node_cache_attrs *cache_attrs);void node_set_perf_attrs (unsigned int nid,struct access_coordinate *coord, -unsigned access); +enum access_coordinate_class access);#else static inline void node_add_cache (unsigned int nid,struct node_cache_attrs *cache_attrs)
@@ -75,7 +87,7 @@ static inline void node_add_cache(unsigned int nid,static inline void node_set_perf_attrs (unsigned int nid,struct access_coordinate *coord, -unsigned access) +enum access_coordinate_class access) { }#endif
@@ -137,7 +149,7 @@ extern void unregister_memory_block_under_nodes(struct memory_block *mem_blk);extern int register_memory_node_under_compute_node (unsigned int mem_nid,unsigned int cpu_nid, -unsigned access); +enum access_coordinate_class access);#else static inline void node_dev_init (void ) {
Signature · 1 line
2.44.0
Dave Jiang
maintainerPATCH v7 3/12 ACPI: HMAT: Introduce 2 levels of generic port access class
In reply to Dave JiangIn order to compute access0 and access1 classes for CXL memory, 2 levels of generic port information must be stored. Access0 will indicate the generic port access coordinates to the closest initiator and access1 will indicate the generic port access coordinates to the cloest CPU.
--- drivers/acpi/numa/hmat.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
drivers/acpi/numa/hmat.c +10 -5
@@ -59,7 +59,8 @@ struct target_cache { };enum { -NODE_ACCESS_CLASS_GENPORT_SINK =ACCESS_COORDINATE_MAX , +NODE_ACCESS_CLASS_GENPORT_SINK_LOCAL =ACCESS_COORDINATE_MAX , +NODE_ACCESS_CLASS_GENPORT_SINK_CPU ,NODE_ACCESS_CLASS_MAX , };
@@ -141,7 +142,7 @@ int acpi_get_genport_coordinates(u32 uid,if (!target)return -ENOENT ; - *coord = target->coord[NODE_ACCESS_CLASS_GENPORT_SINK ]; + *coord = target->coord[NODE_ACCESS_CLASS_GENPORT_SINK_LOCAL ];return 0 ; }
@@ -695,7 +696,8 @@ static void hmat_update_target_attrs(struct memory_target *target,int i;/* Don't update for generic port if there's no device handle */ -if (access ==NODE_ACCESS_CLASS_GENPORT_SINK && +if ((access ==NODE_ACCESS_CLASS_GENPORT_SINK_LOCAL || + access ==NODE_ACCESS_CLASS_GENPORT_SINK_CPU ) && !(*(u16 *)target->gen_port_device_handle))return ;
@@ -736,7 +738,8 @@ static void hmat_update_target_attrs(struct memory_target *target,list_for_each_entry (initiator, &initiators, node) {u32 value; -if (access ==ACCESS_COORDINATE_CPU && +if ((access ==ACCESS_COORDINATE_CPU || + access ==NODE_ACCESS_CLASS_GENPORT_SINK_CPU ) && !initiator->has_cpu) {clear_bit (initiator->processor_pxm, p_nodes);continue ;
@@ -775,7 +778,9 @@ static void hmat_update_generic_target(struct memory_target *target) static DECLARE_BITMAP(p_nodes, MAX_NUMNODES);hmat_update_target_attrs (target, p_nodes, - NODE_ACCESS_CLASS_GENPORT_SINK); + NODE_ACCESS_CLASS_GENPORT_SINK_LOCAL); +hmat_update_target_attrs (target, p_nodes, +NODE_ACCESS_CLASS_GENPORT_SINK_CPU ); }static void hmat_register_target_initiators (struct memory_target *target)
Signature · 1 line
2.44.0
Dave Jiang
maintainerPATCH v7 4/12 ACPI: HMAT / cxl: Add retrieval of generic port coordinates for both access classes
In reply to Dave JiangUpdate acpi_get_genport_coordinates() to allow retrieval of both access classes of the 'struct access_coordinate' for a generic target. The update will allow CXL code to compute access coordinates for both access class.
--- drivers/acpi/numa/hmat.c | 8 ++++++-- drivers/cxl/acpi.c | 8 +++++--- drivers/cxl/core/port.c | 2 +- drivers/cxl/cxl.h | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-)
drivers/acpi/numa/hmat.c +6 -2
@@ -126,7 +126,8 @@ static struct memory_target *acpi_find_genport_target(u32 uid)/** * acpi_get_genport_coordinates - Retrieve the access coordinates for a generic port * @uid: ACPI unique id -* @coord: The access coordinates written back out for the generic port +* @coord: The access coordinates written back out for the generic port. +* Expect 2 levels array. * * Return: 0 on success. Errno on failure. *
@@ -142,7 +143,10 @@ int acpi_get_genport_coordinates(u32 uid,if (!target)return -ENOENT ; - *coord = target->coord[NODE_ACCESS_CLASS_GENPORT_SINK_LOCAL ]; + coord[ACCESS_COORDINATE_LOCAL ] = + target->coord[NODE_ACCESS_CLASS_GENPORT_SINK_LOCAL ]; + coord[ACCESS_COORDINATE_CPU ] = + target->coord[NODE_ACCESS_CLASS_GENPORT_SINK_CPU ];return 0 ; }
drivers/cxl/acpi.c +5 -3
@@ -529,13 +529,15 @@ static int get_genport_coordinates(struct device *dev, struct cxl_dport *dport)if (kstrtou32 (acpi_device_uid (hb),0 , &uid))return -EINVAL ; - rc =acpi_get_genport_coordinates (uid, &dport->hb_coord); + rc =acpi_get_genport_coordinates (uid, dport->hb_coord);if (rc <0 )return rc;/* Adjust back to picoseconds from nanoseconds */ - dport->hb_coord.read_latency *=1000 ; - dport->hb_coord.write_latency *=1000 ; +for (int i =0 ; i <ACCESS_COORDINATE_MAX ; i++) { + dport->hb_coord[i].read_latency *=1000 ; + dport->hb_coord[i].write_latency *=1000 ; + }return 0 ; }
drivers/cxl/core/port.c +1 -1
@@ -2152,7 +2152,7 @@ int cxl_endpoint_get_perf_coordinates(struct cxl_port *port, }/* Augment with the generic port (host bridge) perf data */ -combine_coordinates (&c, &dport->hb_coord); +combine_coordinates (&c, &dport->hb_coord[ACCESS_COORDINATE_LOCAL ]);/* Get the calculated PCI paths bandwidth */ pdev =to_pci_dev (port->uport_dev->parent);
drivers/cxl/cxl.h +1 -1
@@ -671,7 +671,7 @@ struct cxl_dport {struct cxl_port *port;struct cxl_regs regs;struct access_coordinate sw_coord; -struct access_coordinate hb_coord; +struct access_coordinate hb_coord[ACCESS_COORDINATE_MAX ];long link_latency; };
Signature · 1 line
2.44.0
Dave Jiang
maintainerPATCH v7 5/12 cxl: Split out combine_coordinates() for common shared usage
In reply to Dave JiangRefactor the common code of combining coordinates in order to reduce code. Create a new function cxl_cooordinates_combine() it combine two 'struct access_coordinate'.
--- drivers/cxl/core/cdat.c | 32 +++++++++++++++++++++++--------- drivers/cxl/core/port.c | 18 ++---------------- drivers/cxl/cxl.h | 4 ++++ 3 files changed, 29 insertions(+), 25 deletions(-)
drivers/cxl/core/cdat.c +23 -9
@@ -185,15 +185,7 @@ static int cxl_port_perf_data_calculate(struct cxl_port *port,xa_for_each (dsmas_xa, index, dent) {int qos_class; - dent->coord.read_latency = dent->coord.read_latency + - c.read_latency; - dent->coord.write_latency = dent->coord.write_latency + - c.write_latency; - dent->coord.read_bandwidth =min_t (int, c.read_bandwidth, - dent->coord.read_bandwidth); - dent->coord.write_bandwidth =min_t (int, c.write_bandwidth, - dent->coord.write_bandwidth); - +cxl_coordinates_combine (&dent->coord, &dent->coord, &c); dent->entries =1 ; rc = cxl_root->ops->qos_class (cxl_root, &dent->coord,1 , &qos_class);
@@ -484,4 +476,26 @@ void cxl_switch_parse_cdat(struct cxl_port *port) }EXPORT_SYMBOL_NS_GPL (cxl_switch_parse_cdat,CXL ); +/** +* cxl_coordinates_combine - Combine the two input coordinates +* +* @out: Output coordinate of c1 and c2 combined +* @c1: input coordinates +* @c2: input coordinates +*/ +void cxl_coordinates_combine (struct access_coordinate *out, +struct access_coordinate *c1, +struct access_coordinate *c2) +{ +if (c1->write_bandwidth && c2->write_bandwidth) + out->write_bandwidth =min (c1->write_bandwidth, + c2->write_bandwidth); + out->write_latency = c1->write_latency + c2->write_latency; + +if (c1->read_bandwidth && c2->read_bandwidth) + out->read_bandwidth =min (c1->read_bandwidth, + c2->read_bandwidth); + out->read_latency = c1->read_latency + c2->read_latency; +} +MODULE_IMPORT_NS (CXL );
drivers/cxl/core/port.c +2 -16
@@ -2096,20 +2096,6 @@ bool schedule_cxl_memdev_detach(struct cxl_memdev *cxlmd) }EXPORT_SYMBOL_NS_GPL (schedule_cxl_memdev_detach,CXL ); -static void combine_coordinates (struct access_coordinate *c1, -struct access_coordinate *c2) -{ -if (c2->write_bandwidth) - c1->write_bandwidth =min (c1->write_bandwidth, - c2->write_bandwidth); - c1->write_latency += c2->write_latency; - -if (c2->read_bandwidth) - c1->read_bandwidth =min (c1->read_bandwidth, - c2->read_bandwidth); - c1->read_latency += c2->read_latency; -} -/** * cxl_endpoint_get_perf_coordinates - Retrieve performance numbers stored in dports * of CXL path
@@ -2143,7 +2129,7 @@ int cxl_endpoint_get_perf_coordinates(struct cxl_port *port,* nothing to gather. */ while (iter && !is_cxl_root (to_cxl_port (iter->dev.parent))) { -combine_coordinates (&c, &dport->sw_coord); +cxl_coordinates_combine (&c, &c, &dport->sw_coord); c.write_latency += dport->link_latency; c.read_latency += dport->link_latency;
@@ -2152,7 +2138,7 @@ int cxl_endpoint_get_perf_coordinates(struct cxl_port *port, }/* Augment with the generic port (host bridge) perf data */ -combine_coordinates (&c, &dport->hb_coord[ACCESS_COORDINATE_LOCAL ]); +cxl_coordinates_combine (&c, &c, &dport->hb_coord[ACCESS_COORDINATE_LOCAL ]);/* Get the calculated PCI paths bandwidth */ pdev =to_pci_dev (port->uport_dev->parent);
drivers/cxl/cxl.h +4 -0
@@ -882,6 +882,10 @@ int cxl_endpoint_get_perf_coordinates(struct cxl_port *port,void cxl_memdev_update_perf (struct cxl_memdev *cxlmd); +void cxl_coordinates_combine (struct access_coordinate *out, +struct access_coordinate *c1, +struct access_coordinate *c2); +/* * Unit test builds overrides this to __weak, find the 'strong' version * of these symbols in tools/testing/cxl/.
Signature · 1 line
2.44.0
Dave Jiang
maintainerPATCH v7 6/12 cxl: Split out host bridge access coordinates
In reply to Dave JiangThe difference between access class 0 and access class 1 for 'struct access_coordinate', if any, is that class 0 is for the distance from the target to the closest initiator and that class 1 is for the distance from the target to the closest CPU. For CXL memory, the nearest initiator may not necessarily be a CPU node. The performance path from the CXL endpoint to the host bridge should remain the same. However, the numbers extracted and stored from HMAT is the difference for the two access classes. Split out the performance numbers for the host bridge (generic target) from the calculation of the entire path in order to allow calculation of both access classes for a CXL region.
--- drivers/cxl/core/cdat.c | 28 ++++++++++++++++++++++------ drivers/cxl/core/port.c | 35 ++++++++++++++++++++++++++++++++--- drivers/cxl/cxl.h | 2 ++ 3 files changed, 56 insertions(+), 9 deletions(-)
drivers/cxl/core/cdat.c +22 -6
@@ -162,15 +162,22 @@ static int cxl_cdat_endpoint_process(struct cxl_port *port,static int cxl_port_perf_data_calculate (struct cxl_port *port,struct xarray *dsmas_xa) { -struct access_coordinate c; +struct access_coordinate ep_c; +struct access_coordinate coord[ACCESS_COORDINATE_MAX ];struct dsmas_entry *dent;int valid_entries =0 ;unsigned long index;int rc; - rc =cxl_endpoint_get_perf_coordinates (port, &c); + rc =cxl_endpoint_get_perf_coordinates (port, &ep_c);if (rc) { -dev_dbg (&port->dev,"Failed to retrieve perf coordinates.\n" ); +dev_dbg (&port->dev,"Failed to retrieve ep perf coordinates.\n" ); +return rc; + } + + rc =cxl_hb_get_perf_coordinates (port, coord); +if (rc) { +dev_dbg (&port->dev,"Failed to retrieve hb perf coordinates.\n" );return rc; }
@@ -185,10 +192,19 @@ static int cxl_port_perf_data_calculate(struct cxl_port *port,xa_for_each (dsmas_xa, index, dent) {int qos_class; -cxl_coordinates_combine (&dent->coord, &dent->coord, &c); +cxl_coordinates_combine (&dent->coord, &dent->coord, &ep_c); +/* +* Keeping the host bridge coordinates separate from the dsmas +* coordinates in order to allow calculation of access class +* 0 and 1 for region later. +*/ +cxl_coordinates_combine (&coord[ACCESS_COORDINATE_LOCAL ], + &coord[ACCESS_COORDINATE_LOCAL ], + &dent->coord); dent->entries =1 ; - rc = cxl_root->ops->qos_class (cxl_root, &dent->coord,1 , - &qos_class); + rc = cxl_root->ops->qos_class (cxl_root, + &coord[ACCESS_COORDINATE_LOCAL ], +1 , &qos_class);if (rc !=1 )continue ;
drivers/cxl/core/port.c +32 -3
@@ -2096,6 +2096,38 @@ bool schedule_cxl_memdev_detach(struct cxl_memdev *cxlmd) }EXPORT_SYMBOL_NS_GPL (schedule_cxl_memdev_detach,CXL ); +/** +* cxl_hb_get_perf_coordinates - Retrieve performance numbers between initiator +* and host bridge +* +* @port: endpoint cxl_port +* @coord: output access coordinates +* +* Return: errno on failure, 0 on success. +*/ +int cxl_hb_get_perf_coordinates (struct cxl_port *port, +struct access_coordinate *coord) +{ +struct cxl_port *iter = port; +struct cxl_dport *dport; + +if (!is_cxl_endpoint (port)) +return -EINVAL ; + + dport = iter->parent_dport; +while (iter && !is_cxl_root (to_cxl_port (iter->dev.parent))) { + iter =to_cxl_port (iter->dev.parent); + dport = iter->parent_dport; + } + + coord[ACCESS_COORDINATE_LOCAL ] = + dport->hb_coord[ACCESS_COORDINATE_LOCAL ]; + coord[ACCESS_COORDINATE_CPU ] = + dport->hb_coord[ACCESS_COORDINATE_CPU ]; + +return 0 ; +} +/** * cxl_endpoint_get_perf_coordinates - Retrieve performance numbers stored in dports * of CXL path
@@ -2137,9 +2169,6 @@ int cxl_endpoint_get_perf_coordinates(struct cxl_port *port, dport = iter->parent_dport; } -/* Augment with the generic port (host bridge) perf data */ -cxl_coordinates_combine (&c, &c, &dport->hb_coord[ACCESS_COORDINATE_LOCAL ]); -/* Get the calculated PCI paths bandwidth */ pdev =to_pci_dev (port->uport_dev->parent); bw =pcie_bandwidth_available (pdev,NULL ,NULL ,NULL );
drivers/cxl/cxl.h +2 -0
@@ -879,6 +879,8 @@ void cxl_switch_parse_cdat(struct cxl_port *port);int cxl_endpoint_get_perf_coordinates (struct cxl_port *port,struct access_coordinate *coord); +int cxl_hb_get_perf_coordinates (struct cxl_port *port, +struct access_coordinate *coord);void cxl_memdev_update_perf (struct cxl_memdev *cxlmd);
Signature · 1 line
2.44.0
Dave Jiang
maintainerPATCH v7 7/12 cxl: Move QoS class to be calculated from the nearest CPU
In reply to Dave JiangRetrieve the qos_class (QTG ID) using the access coordinates from the nearest CPU rather than the nearst initiator that may not be a CPU. This may be the more appropriate number that applications care about.
For most cases, access0 and access1 have the same values.
--- drivers/cxl/core/cdat.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/cxl/core/cdat.c +3 -3
@@ -198,12 +198,12 @@ static int cxl_port_perf_data_calculate(struct cxl_port *port,* coordinates in order to allow calculation of access class * 0 and 1 for region later. */ -cxl_coordinates_combine (&coord[ACCESS_COORDINATE_LOCAL ], - &coord[ACCESS_COORDINATE_LOCAL ], +cxl_coordinates_combine (&coord[ACCESS_COORDINATE_CPU ], + &coord[ACCESS_COORDINATE_CPU ], &dent->coord); dent->entries =1 ; rc = cxl_root->ops->qos_class (cxl_root, - &coord[ACCESS_COORDINATE_LOCAL ], + &coord[ACCESS_COORDINATE_CPU ],1 , &qos_class);if (rc !=1 )continue ;
Signature · 1 line
2.44.0
Dave Jiang
maintainerPATCH v7 8/12 cxl: Set cxlmd->endpoint before adding port device
In reply to Dave JiangMove setting of cxlmd->endpoint to before calling add_device() on the port device. Otherwise when referencing cxlmd->endpoint in region discovery code that is triggered by the port driver probe function, the endpoint port pointer is not valid.
Current code does not hit this issue yet since cxlmd->endpoint is not being referenced during region discovery. However follow on code that does performance calculations will.
--- drivers/cxl/core/port.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/cxl/core/port.c +1 -1
@@ -822,6 +822,7 @@ static struct cxl_port *__devm_cxl_add_port(struct device *host,*/ port->reg_map = cxlds->reg_map; port->reg_map.host = &port->dev; + cxlmd->endpoint = port; }else if (parent_dport) { rc =dev_set_name (dev,"port%d" , port->id);if (rc)
@@ -1374,7 +1375,6 @@ int cxl_endpoint_autoremove(struct cxl_memdev *cxlmd, struct cxl_port *endpoint)get_device (host);get_device (&endpoint->dev); - cxlmd->endpoint = endpoint; cxlmd->depth = endpoint->depth;return devm_add_action_or_reset (dev, delete_endpoint, cxlmd); }
Signature · 1 line
2.44.0
Dave Jiang
maintainerPATCH v7 9/12 cxl/region: Calculate performance data for a region
In reply to Dave JiangCalculate and store the performance data for a CXL region. Find the worst read and write latency for all the included ranges from each of the devices that attributes to the region and designate that as the latency data. Sum all the read and write bandwidth data for each of the device region and that is the total bandwidth for the region.
The perf list is expected to be constructed before the endpoint decoders are registered and thus there should be no early reading of the entries from the region assemble action. The calling of the region qos calculate function is under the protection of cxl_dpa_rwsem and will ensure that all DPA associated work has completed.
--- drivers/cxl/core/cdat.c | 65 +++++++++++++++++++++++++++++++++++++++ drivers/cxl/core/region.c | 2 ++ drivers/cxl/cxl.h | 4 +++ 3 files changed, 71 insertions(+)
drivers/cxl/core/cdat.c +65 -0
@@ -9,6 +9,7 @@#include "cxlmem.h" #include "core.h" #include "cxl.h" +#include "core.h" struct dsmas_entry {struct range dpa_range;
@@ -515,3 +516,67 @@ void cxl_coordinates_combine(struct access_coordinate *out, }MODULE_IMPORT_NS (CXL ); + +void cxl_region_perf_data_calculate (struct cxl_region *cxlr, +struct cxl_endpoint_decoder *cxled) +{ +struct cxl_memdev *cxlmd =cxled_to_memdev (cxled); +struct cxl_port *port = cxlmd->endpoint; +struct cxl_dev_state *cxlds = cxlmd->cxlds; +struct cxl_memdev_state *mds =to_cxl_memdev_state (cxlds); +struct access_coordinate hb_coord[ACCESS_COORDINATE_MAX ]; +struct access_coordinate coord; +struct range dpa = { + .start = cxled->dpa_res->start, + .end = cxled->dpa_res->end, + }; +struct cxl_dpa_perf *perf; +int rc; + +switch (cxlr->mode) { +case CXL_DECODER_RAM : + perf = &mds->ram_perf; +break ; +case CXL_DECODER_PMEM : + perf = &mds->pmem_perf; +break ; +default : +return ; + } + +lockdep_assert_held (&cxl_dpa_rwsem); + +if (!range_contains (&perf->dpa_range, &dpa)) +return ; + + rc =cxl_hb_get_perf_coordinates (port, hb_coord); +if (rc) { +dev_dbg (&port->dev,"Failed to retrieve hb perf coordinates.\n" ); +return ; + } + +for (int i =0 ; i <ACCESS_COORDINATE_MAX ; i++) { +/* Pickup the host bridge coords */ +cxl_coordinates_combine (&coord, &hb_coord[i], &perf->coord); + +/* Get total bandwidth and the worst latency for the cxl region */ + cxlr->coord[i].read_latency = max_t(unsigned int, + cxlr->coord[i].read_latency, + coord.read_latency); + cxlr->coord[i].write_latency = max_t(unsigned int, + cxlr->coord[i].write_latency, + coord.write_latency); + cxlr->coord[i].read_bandwidth += coord.read_bandwidth; + cxlr->coord[i].write_bandwidth += coord.write_bandwidth; + +/* +* Convert latency to nanosec from picosec to be consistent +* with the resulting latency coordinates computed by the +* HMAT_REPORTING code. +*/ + cxlr->coord[i].read_latency = +DIV_ROUND_UP (cxlr->coord[i].read_latency,1000 ); + cxlr->coord[i].write_latency = +DIV_ROUND_UP (cxlr->coord[i].write_latency,1000 ); + } +}
drivers/cxl/core/region.c +2 -0
@@ -1752,6 +1752,8 @@ static int cxl_region_attach(struct cxl_region *cxlr,return -EINVAL ; } +cxl_region_perf_data_calculate (cxlr, cxled); +if (test_bit (CXL_REGION_F_AUTO , &cxlr->flags)) {int i;
drivers/cxl/cxl.h +4 -0
@@ -517,6 +517,7 @@ struct cxl_region_params {* @cxlr_pmem: (for pmem regions) cached copy of the nvdimm bridge * @flags: Region state flags * @params: active + config params for the region +* @coord: QoS access coordinates for the region */ struct cxl_region {struct device dev;
@@ -527,6 +528,7 @@ struct cxl_region {struct cxl_pmem_region *cxlr_pmem;unsigned long flags;struct cxl_region_params params; +struct access_coordinate coord[ACCESS_COORDINATE_MAX ]; };struct cxl_nvdimm_bridge {
@@ -881,6 +883,8 @@ int cxl_endpoint_get_perf_coordinates(struct cxl_port *port, struct access_coordinate *coord);int cxl_hb_get_perf_coordinates (struct cxl_port *port,struct access_coordinate *coord); +void cxl_region_perf_data_calculate (struct cxl_region *cxlr, +struct cxl_endpoint_decoder *cxled);void cxl_memdev_update_perf (struct cxl_memdev *cxlmd);
Signature · 1 line
2.44.0
Dave Jiang
maintainerPATCH v7 10/12 cxl/region: Add sysfs attribute for locality attributes of CXL regions
In reply to Dave JiangAdd read/write latencies and bandwidth sysfs attributes for the enabled CXL region. The bandwidth is the aggregated bandwidth of all devices that contribute to the CXL region. The latency is the worst latency of the device amongst all the devices that contribute to the CXL region.
---
v7:
- Remove comma after NULL in array listing. (Jonathan)
--- Documentation/ABI/testing/sysfs-bus-cxl | 34 +++++++++ drivers/cxl/core/region.c | 94 +++++++++++++++++++++++++ 2 files changed, 128 insertions(+)
Documentation/ABI/testing/sysfs-bus-cxl +34 -0
@@ -552,3 +552,37 @@ Description: attribute is only visible for devices supporting the capability. The retrieved errors are logged as kernel events when cxl_poison event tracing is enabled. + + +What: /sys/bus/cxl/devices/regionZ/accessY/read_bandwidth + /sys/bus/cxl/devices/regionZ/accessY/write_banwidth +Date: Jan, 2024 +KernelVersion: v6.9 +Contact: [email protected] +Description: + (RO) The aggregated read or write bandwidth of the region. The + number is the accumulated read or write bandwidth of all CXL memory + devices that contributes to the region in MB/s. It is + identical data that should appear in + /sys/devices/system/node/nodeX/accessY/initiators/read_bandwidth or + /sys/devices/system/node/nodeX/accessY/initiators/write_bandwidth. + See Documentation/ABI/stable/sysfs-devices-node. access0 provides + the number to the closest initiator and access1 provides the + number to the closest CPU. + + +What: /sys/bus/cxl/devices/regionZ/accessY/read_latency + /sys/bus/cxl/devices/regionZ/accessY/write_latency +Date: Jan, 2024 +KernelVersion: v6.9 +Contact: [email protected] +Description: + (RO) The read or write latency of the region. The number is + the worst read or write latency of all CXL memory devices that + contributes to the region in nanoseconds. It is identical data + that should appear in + /sys/devices/system/node/nodeX/accessY/initiators/read_latency or + /sys/devices/system/node/nodeX/accessY/initiators/write_latency. + See Documentation/ABI/stable/sysfs-devices-node. access0 provides + the number to the closest initiator and access1 provides the + number to the closest CPU.
drivers/cxl/core/region.c +94 -0
106 lines not on this page · raw message
Signature · 1 line
2.44.0
Dave Jiang
maintainerPATCH v7 11/12 cxl/region: Add memory hotplug notifier for cxl region
In reply to Dave JiangWhen the CXL region is formed, the driver would computed 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().
---
v7:
- Fix typo in commit log (Jonathan)
- Move memory_notifier registration to devm_cxl_add_region(). (Dan)
--- drivers/acpi/numa/hmat.c | 34 ++++++++++++++++++++ drivers/cxl/core/cdat.c | 6 ++++ drivers/cxl/core/core.h | 3 ++ drivers/cxl/core/region.c | 68 +++++++++++++++++++++++++++++++++++++++ drivers/cxl/cxl.h | 3 ++ include/linux/acpi.h | 12 +++++++ include/linux/memory.h | 1 + 7 files changed, 127 insertions(+)
drivers/acpi/numa/hmat.c +34 -0
@@ -74,6 +74,7 @@ struct memory_target {struct node_cache_attrs cache_attrs;u8 gen_port_device_handle[ACPI_SRAT_DEVICE_HANDLE_SIZE ];bool registered; +bool ext_updated;/* externally updated */ };struct memory_initiator {
@@ -328,6 +329,35 @@ static void hmat_update_target_access(struct memory_target *target, } } +int hmat_update_target_coordinates (int nid,struct access_coordinate *coord, +enum access_coordinate_class access) +{ +struct memory_target *target; +int pxm; + +if (nid ==NUMA_NO_NODE ) +return -EINVAL ; + + pxm =node_to_pxm (nid); +guard (mutex)(&target_lock); + target =find_mem_target (pxm); +if (!target) +return -ENODEV ; + +hmat_update_target_access (target,ACPI_HMAT_READ_LATENCY , + coord->read_latency, access); +hmat_update_target_access (target,ACPI_HMAT_WRITE_LATENCY , + coord->write_latency, access); +hmat_update_target_access (target,ACPI_HMAT_READ_BANDWIDTH , + coord->read_bandwidth, access); +hmat_update_target_access (target,ACPI_HMAT_WRITE_BANDWIDTH , + coord->write_bandwidth, access); + target->ext_updated = true; + +return 0 ; +} +EXPORT_SYMBOL_GPL (hmat_update_target_coordinates); +static __init void hmat_add_locality (struct acpi_hmat_locality *hmat_loc) {struct memory_locality *loc;
@@ -699,6 +729,10 @@ static void hmat_update_target_attrs(struct memory_target *target,u32 best =0 ;int i; +/* Don't update if an external agent has changed the data. */ +if (target->ext_updated) +return ; +/* Don't update for generic port if there's no device handle */ if ((access == NODE_ACCESS_CLASS_GENPORT_SINK_LOCAL || access == NODE_ACCESS_CLASS_GENPORT_SINK_CPU) &&
drivers/cxl/core/cdat.c +6 -0
@@ -580,3 +580,9 @@ void cxl_region_perf_data_calculate(struct cxl_region *cxlr,DIV_ROUND_UP (cxlr->coord[i].write_latency,1000 ); } } + +int cxl_update_hmat_access_coordinates (int nid,struct cxl_region *cxlr, +enum access_coordinate_class access) +{ +return hmat_update_target_coordinates (nid, &cxlr->coord[access], access); +}
drivers/cxl/core/core.h +3 -0
@@ -90,4 +90,7 @@ enum cxl_poison_trace_type {long cxl_pci_get_latency (struct pci_dev *pdev); +int cxl_update_hmat_access_coordinates (int nid,struct cxl_region *cxlr, +enum access_coordinate_class access); +#endif /* __CXL_CORE_H__ */
drivers/cxl/core/region.c +68 -0
104 lines not on this page · raw message
drivers/cxl/cxl.h +3 -0
@@ -6,6 +6,7 @@#include <linux/libnvdimm.h> #include <linux/bitfield.h> +#include <linux/notifier.h> #include <linux/bitops.h> #include <linux/log2.h> #include <linux/node.h>
@@ -518,6 +519,7 @@ struct cxl_region_params {* @flags: Region state flags * @params: active + config params for the region * @coord: QoS access coordinates for the region +* @memory_notifier: notifier for setting the access coordinates to node */ struct cxl_region {struct device dev;
@@ -529,6 +531,7 @@ struct cxl_region {unsigned long flags;struct cxl_region_params params;struct access_coordinate coord[ACCESS_COORDINATE_MAX ]; +struct notifier_block memory_notifier; };struct cxl_nvdimm_bridge {
include/linux/acpi.h +12 -0
@@ -1547,4 +1547,16 @@ static inline void acpi_use_parent_companion(struct device *dev) ACPI_COMPANION_SET(dev, ACPI_COMPANION(dev->parent)); } +#ifdef CONFIG_ACPI_HMAT +int hmat_update_target_coordinates (int nid,struct access_coordinate *coord, +enum access_coordinate_class access); +#else +static inline int hmat_update_target_coordinates (int nid, +struct access_coordinate *coord, +enum access_coordinate_class access) +{ +return -EOPNOTSUPP ; +} +#endif +#endif /*_LINUX_ACPI_H*/
include/linux/memory.h +1 -0
@@ -114,6 +114,7 @@ struct mem_section;#define DEFAULT_CALLBACK_PRI 0#define SLAB_CALLBACK_PRI 1#define HMAT_CALLBACK_PRI 2 +#define CXL_CALLBACK_PRI 5#define MM_COMPUTE_BATCH_PRI 10#define CPUSET_CALLBACK_PRI 10#define MEMTIER_HOTPLUG_PRI 100
Signature · 1 line
2.44.0
Re: [PATCH v7 11/12] cxl/region: Add memory hotplug notifier for cxl region
Quoted 1 line · Dave Jiang
When the CXL region is formed, the driver would computed the performance
s/would computed/computes/
...fixed that up locally.
Quoted 24 lines
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 theHMAT_REPORTINGcode.Add
CXL_CALLBACK_PRIfor a memory hotplug callback priority. Set the priority number to be called beforeHMAT_CALLBACK_PRI. The CXL update must happen beforehmat_callback().A new
HMAT_REPORTINGhelperhmat_update_target_coordinates()is added in order to allow CXL to update thememory_targetaccess coordinates.A new
ext_updatedmember is added to thememory_targetto indicate that the access coordinates within thememory_targethas been updated by an external agent such as CXL. This prevents data being overwritten by thehmat_update_target_attrs()triggered byhmat_callback().Cc Andrew Morton <[email protected]>Cc Rafael J. Wysocki <[email protected]>Reviewed-by "Huang, Ying" <[email protected]>Reviewed-by Jonathan Cameron <[email protected]>Tested-by Jonathan Cameron <[email protected]>Signed-off-by Dave Jiang <[email protected]>
Quoted 4 lines
---
v7:
- Fix typo in commit log (Jonathan)
- Movememory_notifierregistration todevm_cxl_add_region(). (Dan)
With that change, looks good.
Dave Jiang
maintainerPATCH v7 12/12 cxl/region: Deal with numa nodes not enumerated by SRAT
In reply to Dave JiangFor the numa nodes that are not created by SRAT, no memory_target is allocated and is not managed by the HMAT_REPORTING code. Therefore hmat_callback() memory hotplug notifier will exit early on those NUMA nodes. The CXL memory hotplug notifier will need to call node_set_perf_attrs() directly in order to setup the access sysfs attributes.
In acpi_numa_init(), the last proximity domain (pxm) id created by SRAT is stored. Add a helper function acpi_node_backed_by_real_pxm() in order to check if a NUMA node id is defined by SRAT or created by CFMWS.
node_set_perf_attrs() symbol is exported to allow update of perf attribs for a node. The sysfs path of /sys/devices/system/node/nodeX/access0/initiators/* is created by node_set_perf_attrs() for the various attributes where nodeX is matched to the NUMA node of the CXL region.
---
v7:
- Fix typo is commit log. (Jonathan)
--- drivers/acpi/numa/srat.c | 11 +++++++++++ drivers/base/node.c | 1 + drivers/cxl/core/cdat.c | 5 +++++ drivers/cxl/core/core.h | 1 + drivers/cxl/core/region.c | 7 ++++++- include/linux/acpi.h | 9 +++++++++ 6 files changed, 33 insertions(+), 1 deletion(-)
drivers/acpi/numa/srat.c +11 -0
@@ -29,6 +29,8 @@ static int node_to_pxm_map[MAX_NUMNODES]unsigned char acpi_srat_revision__initdata ;static int acpi_numa__initdata ; +static int last_real_pxm; +void __init disable_srat (void ) { acpi_numa =-1 ;
@@ -536,6 +538,7 @@ int __init acpi_numa_init(void)if (node_to_pxm_map[i] > fake_pxm) fake_pxm = node_to_pxm_map[i]; } + last_real_pxm = fake_pxm; fake_pxm++;acpi_table_parse_cedt (ACPI_CEDT_TYPE_CFMWS , acpi_parse_cfmws, &fake_pxm);
@@ -547,6 +550,14 @@ int __init acpi_numa_init(void)return 0 ; } +bool acpi_node_backed_by_real_pxm (int nid) +{ +int pxm =node_to_pxm (nid); + +return pxm <= last_real_pxm; +} +EXPORT_SYMBOL_GPL (acpi_node_backed_by_real_pxm); +static int acpi_get_pxm (acpi_handle h) {unsigned long long pxm;
drivers/base/node.c +1 -0
@@ -215,6 +215,7 @@ void node_set_perf_attrs(unsigned int nid, struct access_coordinate *coord, } } } +EXPORT_SYMBOL_GPL (node_set_perf_attrs);/** * struct node_cache_info - Internal tracking for memory node caches
drivers/cxl/core/cdat.c +5 -0
@@ -586,3 +586,8 @@ int cxl_update_hmat_access_coordinates(int nid, struct cxl_region *cxlr, {return hmat_update_target_coordinates (nid, &cxlr->coord[access], access); } + +bool cxl_need_node_perf_attrs_update (int nid) +{ +return !acpi_node_backed_by_real_pxm (nid); +}
drivers/cxl/core/core.h +1 -0
@@ -92,5 +92,6 @@ long cxl_pci_get_latency(struct pci_dev *pdev);int cxl_update_hmat_access_coordinates (int nid,struct cxl_region *cxlr,enum access_coordinate_class access); +bool cxl_need_node_perf_attrs_update (int nid);#endif /* __CXL_CORE_H__ */
drivers/cxl/core/region.c +6 -1
@@ -2279,7 +2279,12 @@ static bool cxl_region_update_coordinates(struct cxl_region *cxlr, int nid)for (int i =0 ; i <ACCESS_COORDINATE_MAX ; i++) {if (cxlr->coord[i].read_bandwidth) { - rc =cxl_update_hmat_access_coordinates (nid, cxlr, i); + rc =0 ; +if (cxl_need_node_perf_attrs_update (nid)) +node_set_perf_attrs (nid, &cxlr->coord[i], i); +else + rc =cxl_update_hmat_access_coordinates (nid, cxlr, i); +if (rc ==0 ) cset++; }
include/linux/acpi.h +9 -0
@@ -1559,4 +1559,13 @@ static inline int hmat_update_target_coordinates(int nid, }#endif +#ifdef CONFIG_ACPI_NUMA +bool acpi_node_backed_by_real_pxm (int nid); +#else +static inline bool acpi_node_backed_by_real_pxm (int nid) +{ +return false; +} +#endif +#endif /*_LINUX_ACPI_H*/
Signature · 1 line
2.44.0
Re: [PATCH v7 12/12] cxl/region: Deal with numa nodes not enumerated by SRAT
Quoted 56 lines · Dave Jiang
For the numa nodes that are not created by SRAT, no
memory_targetis allocated and is not managed by theHMAT_REPORTINGcode. Thereforehmat_callback()memory hotplug notifier will exit early on those NUMA nodes. The CXL memory hotplug notifier will need to callnode_set_perf_attrs()directly in order to setup the access sysfs attributes.In
acpi_numa_init(), the last proximity domain (pxm) id created by SRAT is stored. Add a helper functionacpi_node_backed_by_real_pxm()in order to check if a NUMA node id is defined by SRAT or created by CFMWS.
node_set_perf_attrs()symbol is exported to allow update of perf attribs for a node. The sysfs path of/sys/devices/system/node/nodeX/access0/initiators/*is created bynode_set_perf_attrs()for the various attributes where nodeX is matched to the NUMA node of the CXL region.Cc Rafael J. Wysocki <[email protected]>Reviewed-by Alison Schofield <[email protected]>Reviewed-by Jonathan Cameron <[email protected]>Tested-by Jonathan Cameron <[email protected]>Signed-off-by Dave Jiang <[email protected]>---
v7:
- Fix typo is commit log. (Jonathan)--- drivers/acpi/numa/srat.c | 11 +++++++++++ drivers/base/node.c | 1 + drivers/cxl/core/cdat.c | 5 +++++ drivers/cxl/core/core.h | 1 + drivers/cxl/core/region.c | 7 ++++++- include/linux/acpi.h | 9 +++++++++ 6 files changed, 33 insertions(+), 1 deletion(-)drivers/acpi/numa/srat.c +3
-0@@ -29,6 +29,8 @@ static int node_to_pxm_map[MAX_NUMNODES]unsigned char acpi_srat_revision__initdata ;static int acpi_numa__initdata ; +static int last_real_pxm; +void __init disable_srat (void ) { acpi_numa =-1 ;@@ -536,6 +538,7 @@ int __init acpi_numa_init(void)if (node_to_pxm_map[i] > fake_pxm) fake_pxm = node_to_pxm_map[i]; } + last_real_pxm = fake_pxm; fake_pxm++;acpi_table_parse_cedt (ACPI_CEDT_TYPE_CFMWS , acpi_parse_cfmws, &fake_pxm);
drivers/acpi/numa/srat.c int __init acpi_numa_init(void) · line 559
Quoted 10 lines
drivers/acpi/numa/srat.c +7
-0@@ -547,6 +550,14 @@ int __init acpi_numa_init(void)return 0 ; } +bool acpi_node_backed_by_real_pxm (int nid) +{ +int pxm =node_to_pxm (nid); + +return pxm <= last_real_pxm; +} +EXPORT_SYMBOL_GPL (acpi_node_backed_by_real_pxm);
I quibble with this naming because it is not about "real" vs "fake" is about HMAT decorated PXMs vs not, but I do not want to hold up v6.9 consideration for this quibble.
It can be addressed when / if cxl_need_node_perf_attrs_update() ever interoperates with a non ACPI platform.