hulk inclusion category: feature bugzilla: https://gitee.com/openeuler/kernel/issues/I67QNJ CVE: NA
--------------------------------------------------
Provide additional memory device topology information in hisi_hbmdev. This memory topology informaton can provide useful information for userspace to select the closest memory device to a certain cpu.
Signed-off-by: Zhang Zekun zhangzekun11@huawei.com --- drivers/soc/hisilicon/Kconfig | 9 +++-- drivers/soc/hisilicon/hisi_hbmdev.c | 61 +++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 3 deletions(-)
diff --git a/drivers/soc/hisilicon/Kconfig b/drivers/soc/hisilicon/Kconfig index 3e5cf16be223..6792f4a4f62b 100644 --- a/drivers/soc/hisilicon/Kconfig +++ b/drivers/soc/hisilicon/Kconfig @@ -8,9 +8,12 @@ config HISI_HBMDEV depends on ACPI_HOTPLUG_MEMORY select ACPI_CONTAINER help - This driver add extra supports for memory devices. The driver - provides methods for userpace to control the power of memory - devices in a container. + This driver add two extra supports for memory devices. The driver + provides methods for userpace to control the power of memory devices + in a container. Besides, it provides extra locality information + between cpus and memory devices for userspace, which can take + advantage of this functionality to select the closet memory device + to a certain cpu.
To compile this driver as a module, choose M here: the module will be called hisi_hbmdev. diff --git a/drivers/soc/hisilicon/hisi_hbmdev.c b/drivers/soc/hisilicon/hisi_hbmdev.c index 0a0977956042..a4b72d232e19 100644 --- a/drivers/soc/hisilicon/hisi_hbmdev.c +++ b/drivers/soc/hisilicon/hisi_hbmdev.c @@ -8,6 +8,9 @@ #include <linux/nodemask.h> #include <linux/acpi.h> #include <linux/container.h> +#include <linux/node.h> +#include <linux/arch_topology.h> +#include <linux/memory_hotplug.h>
#include "hisi_internal.h"
@@ -21,11 +24,67 @@ struct cdev_node {
struct memory_dev { struct kobject *memdev_kobj; + struct kobject *topo_kobj; struct cdev_node cdev_list; + nodemask_t cluster_cpumask[MAX_NUMNODES]; };
static struct memory_dev *mdev;
+static ssize_t memory_locality_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + int i, count = 0; + + for (i = 0; i < MAX_NUMNODES; i++) { + if (hotplug_mdev[i] != NULL && !nodes_empty(mdev->cluster_cpumask[i])) { + count += sysfs_emit_at(buf, count, "%d %*pbl\n", i, + nodemask_pr_args(&mdev->cluster_cpumask[i])); + } + } + + return count; +} + +static struct kobj_attribute memory_locality_attribute = + __ATTR(memory_locality, 0444, memory_locality_show, NULL); + +static void memory_topo_init(void) +{ + int ret, nid, cluster_id, cpu; + struct acpi_device *adev; + nodemask_t mask; + + for (nid = 0; nid < MAX_NUMNODES; nid++) { + if (!hotplug_mdev[nid]) + continue; + + adev = hotplug_mdev[nid]; + ret = fwnode_property_read_u32(acpi_fwnode_handle(adev), + "cluster-id", &cluster_id); + if (ret < 0) { + pr_debug("Failed to read cluster id\n"); + return; + } + + nodes_clear(mask); + for_each_possible_cpu(cpu) { + if (topology_cluster_id(cpu) == cluster_id) + node_set(cpu, mask); + } + mdev->cluster_cpumask[nid] = mask; + } + + mdev->topo_kobj = kobject_create_and_add("memory_topo", mdev->memdev_kobj); + if (!mdev->topo_kobj) + return; + + ret = sysfs_create_file(mdev->topo_kobj, &memory_locality_attribute.attr); + if (ret) + kobject_put(mdev->topo_kobj); +} + static int get_pxm(struct acpi_device *acpi_device, void *arg) { acpi_handle handle = acpi_device->handle; @@ -224,6 +283,7 @@ static int __init mdev_init(void) return -ENOMEM; }
+ memory_topo_init(); return ret; } module_init(mdev_init); @@ -232,6 +292,7 @@ static void __exit mdev_exit(void) { container_remove(); kobject_put(mdev->memdev_kobj); + kobject_put(mdev->topo_kobj); kfree(mdev); } module_exit(mdev_exit);