@@ -12,7 +12,7 @@ obj-y += power/
obj-$(CONFIG_ISA_BUS_API) += isa.o
obj-y += firmware_loader/
obj-$(CONFIG_NUMA) += node.o
-obj-$(CONFIG_HMS) += hms.o hms-target.o hms-initiator.o
+obj-$(CONFIG_HMS) += hms.o hms-target.o hms-initiator.o hms-link.o
obj-$(CONFIG_MEMORY_HOTPLUG_SPARSE) += memory.o
ifeq ($(CONFIG_SYSFS),y)
obj-$(CONFIG_MODULES) += module.o
new file mode 100644
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2018 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Authors:
+ * Jérôme Glisse <jglisse@redhat.com>
+ */
+/* Heterogeneous memory system (HMS) see Documentation/vm/hms.rst */
+#include <linux/capability.h>
+#include <linux/topology.h>
+#include <linux/uaccess.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/hms.h>
+
+
+struct hms_link *hms_object_to_link(struct hms_object *object)
+{
+ if (object == NULL)
+ return NULL;
+
+ if (object->type != HMS_LINK)
+ return NULL;
+ return container_of(object, struct hms_link, object);
+}
+
+static inline struct hms_link *device_to_hms_link(struct device *device)
+{
+ if (device == NULL)
+ return NULL;
+
+ return hms_object_to_link(to_hms_object(device));
+}
+
+struct hms_link *hms_link_find_locked(unsigned uid)
+{
+ struct hms_object *object = hms_object_find_locked(uid);
+ struct hms_link *link;
+
+ link = hms_object_to_link(object);
+ if (link)
+ return link;
+ hms_object_put(object);
+ return NULL;
+}
+
+struct hms_link *hms_link_find(unsigned uid)
+{
+ struct hms_object *object = hms_object_find(uid);
+ struct hms_link *link;
+
+ link = hms_object_to_link(object);
+ if (link)
+ return link;
+ hms_object_put(object);
+ return NULL;
+}
+
+static void hms_link_release(struct device *device)
+
+{
+ struct hms_link *link = device_to_hms_link(device);
+
+ hms_object_release(&link->object);
+ kfree(link);
+}
+
+static ssize_t hms_link_show_uid(struct device *device,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct hms_link *link = device_to_hms_link(device);
+
+ if (link == NULL)
+ return -EINVAL;
+
+ return sprintf(buf, "%d\n", link->object.uid);
+}
+
+static DEVICE_ATTR(uid, 0444, hms_link_show_uid, NULL);
+
+static struct attribute *hms_link_attrs[] = {
+ &dev_attr_uid.attr,
+ NULL
+};
+
+static struct attribute_group hms_link_attr_group = {
+ .attrs = hms_link_attrs,
+};
+
+static const struct attribute_group *hms_link_attr_groups[] = {
+ &hms_link_attr_group,
+ NULL,
+};
+
+void hms_link_register(struct hms_link **linkp, struct device *parent,
+ unsigned version)
+{
+ struct hms_link *link;
+
+ *linkp = NULL;
+ link = kzalloc(sizeof(*link), GFP_KERNEL);
+ if (link == NULL)
+ return;
+
+ if (hms_object_init(&link->object, parent, HMS_LINK, version,
+ hms_link_release, hms_link_attr_groups)) {
+ kfree(link);
+ link = NULL;
+ }
+
+ *linkp = link;
+}
+EXPORT_SYMBOL(hms_link_register);
+
+void hms_unlink_initiator(struct hms_link *link,
+ struct hms_initiator *initiator)
+{
+ if (link == NULL || initiator == NULL)
+ return;
+ if (link->object.type != HMS_LINK)
+ return;
+ if (initiator->object.type != HMS_INITIATOR)
+ return;
+ hms_object_unlink(&link->object, &initiator->object);
+}
+EXPORT_SYMBOL(hms_unlink_initiator);
+
+void hms_unlink_target(struct hms_link *link, struct hms_target *target)
+{
+ if (link == NULL || target == NULL)
+ return;
+ if (link->object.type != HMS_LINK || target->object.type != HMS_TARGET)
+ return;
+ hms_object_unlink(&link->object, &target->object);
+}
+EXPORT_SYMBOL(hms_unlink_target);
+
+int hms_link_initiator(struct hms_link *link, struct hms_initiator *initiator)
+{
+ if (link == NULL || initiator == NULL)
+ return -EINVAL;
+ if (link->object.type != HMS_LINK)
+ return -EINVAL;
+ if (initiator->object.type != HMS_INITIATOR)
+ return -EINVAL;
+ return hms_object_link(&link->object, &initiator->object);
+}
+EXPORT_SYMBOL(hms_link_initiator);
+
+int hms_link_target(struct hms_link *link, struct hms_target *target)
+{
+ if (link == NULL || target == NULL)
+ return -EINVAL;
+ if (link->object.type != HMS_LINK || target->object.type != HMS_TARGET)
+ return -EINVAL;
+ return hms_object_link(&link->object, &target->object);
+}
+EXPORT_SYMBOL(hms_link_target);
+
+void hms_link_unregister(struct hms_link **linkp)
+{
+ struct hms_link *link = *linkp;
+
+ *linkp = NULL;
+ if (link == NULL)
+ return;
+
+ hms_object_unregister(&link->object);
+}
+EXPORT_SYMBOL(hms_link_unregister);
@@ -100,6 +100,21 @@ static inline void hms_target_put(struct hms_target *target)
}
+struct hms_link {
+ struct hms_object object;
+};
+
+struct hms_link *hms_object_to_link(struct hms_object *object);
+void hms_unlink_initiator(struct hms_link *link,
+ struct hms_initiator *initiator);
+void hms_unlink_target(struct hms_link *link, struct hms_target *target);
+int hms_link_initiator(struct hms_link *link, struct hms_initiator *initiator);
+int hms_link_target(struct hms_link *link, struct hms_target *target);
+void hms_link_register(struct hms_link **linkp, struct device *parent,
+ unsigned version);
+void hms_link_unregister(struct hms_link **linkp);
+
+
int hms_init(void);
@@ -116,6 +131,14 @@ int hms_init(void);
#define hms_target_unregister(targetp)
+#define hms_unlink_initiator(link, initiator)
+#define hms_unlink_target(link, target)
+#define hms_link_initiator(link, initiator)
+#define hms_link_target(link, target)
+#define hms_link_register(linkp)
+#define hms_link_unregister(linkp)
+
+
static inline int hms_init(void)
{
return 0;