|
@@ -0,0 +1,126 @@
|
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
|
+/*
|
|
|
+ * Adjunct processor matrix VFIO device driver callbacks.
|
|
|
+ *
|
|
|
+ * Copyright IBM Corp. 2018
|
|
|
+ *
|
|
|
+ * Author(s): Tony Krowiak <akrowiak@linux.ibm.com>
|
|
|
+ * Halil Pasic <pasic@linux.ibm.com>
|
|
|
+ * Pierre Morel <pmorel@linux.ibm.com>
|
|
|
+ */
|
|
|
+#include <linux/string.h>
|
|
|
+#include <linux/vfio.h>
|
|
|
+#include <linux/device.h>
|
|
|
+#include <linux/list.h>
|
|
|
+#include <linux/ctype.h>
|
|
|
+#include <asm/zcrypt.h>
|
|
|
+
|
|
|
+#include "vfio_ap_private.h"
|
|
|
+
|
|
|
+#define VFIO_AP_MDEV_TYPE_HWVIRT "passthrough"
|
|
|
+#define VFIO_AP_MDEV_NAME_HWVIRT "VFIO AP Passthrough Device"
|
|
|
+
|
|
|
+static void vfio_ap_matrix_init(struct ap_config_info *info,
|
|
|
+ struct ap_matrix *matrix)
|
|
|
+{
|
|
|
+ matrix->apm_max = info->apxa ? info->Na : 63;
|
|
|
+ matrix->aqm_max = info->apxa ? info->Nd : 15;
|
|
|
+ matrix->adm_max = info->apxa ? info->Nd : 15;
|
|
|
+}
|
|
|
+
|
|
|
+static int vfio_ap_mdev_create(struct kobject *kobj, struct mdev_device *mdev)
|
|
|
+{
|
|
|
+ struct ap_matrix_mdev *matrix_mdev;
|
|
|
+
|
|
|
+ if ((atomic_dec_if_positive(&matrix_dev->available_instances) < 0))
|
|
|
+ return -EPERM;
|
|
|
+
|
|
|
+ matrix_mdev = kzalloc(sizeof(*matrix_mdev), GFP_KERNEL);
|
|
|
+ if (!matrix_mdev) {
|
|
|
+ atomic_inc(&matrix_dev->available_instances);
|
|
|
+ return -ENOMEM;
|
|
|
+ }
|
|
|
+
|
|
|
+ vfio_ap_matrix_init(&matrix_dev->info, &matrix_mdev->matrix);
|
|
|
+ mdev_set_drvdata(mdev, matrix_mdev);
|
|
|
+ mutex_lock(&matrix_dev->lock);
|
|
|
+ list_add(&matrix_mdev->node, &matrix_dev->mdev_list);
|
|
|
+ mutex_unlock(&matrix_dev->lock);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int vfio_ap_mdev_remove(struct mdev_device *mdev)
|
|
|
+{
|
|
|
+ struct ap_matrix_mdev *matrix_mdev = mdev_get_drvdata(mdev);
|
|
|
+
|
|
|
+ mutex_lock(&matrix_dev->lock);
|
|
|
+ list_del(&matrix_mdev->node);
|
|
|
+ mutex_unlock(&matrix_dev->lock);
|
|
|
+
|
|
|
+ kfree(matrix_mdev);
|
|
|
+ mdev_set_drvdata(mdev, NULL);
|
|
|
+ atomic_inc(&matrix_dev->available_instances);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t name_show(struct kobject *kobj, struct device *dev, char *buf)
|
|
|
+{
|
|
|
+ return sprintf(buf, "%s\n", VFIO_AP_MDEV_NAME_HWVIRT);
|
|
|
+}
|
|
|
+
|
|
|
+MDEV_TYPE_ATTR_RO(name);
|
|
|
+
|
|
|
+static ssize_t available_instances_show(struct kobject *kobj,
|
|
|
+ struct device *dev, char *buf)
|
|
|
+{
|
|
|
+ return sprintf(buf, "%d\n",
|
|
|
+ atomic_read(&matrix_dev->available_instances));
|
|
|
+}
|
|
|
+
|
|
|
+MDEV_TYPE_ATTR_RO(available_instances);
|
|
|
+
|
|
|
+static ssize_t device_api_show(struct kobject *kobj, struct device *dev,
|
|
|
+ char *buf)
|
|
|
+{
|
|
|
+ return sprintf(buf, "%s\n", VFIO_DEVICE_API_AP_STRING);
|
|
|
+}
|
|
|
+
|
|
|
+MDEV_TYPE_ATTR_RO(device_api);
|
|
|
+
|
|
|
+static struct attribute *vfio_ap_mdev_type_attrs[] = {
|
|
|
+ &mdev_type_attr_name.attr,
|
|
|
+ &mdev_type_attr_device_api.attr,
|
|
|
+ &mdev_type_attr_available_instances.attr,
|
|
|
+ NULL,
|
|
|
+};
|
|
|
+
|
|
|
+static struct attribute_group vfio_ap_mdev_hwvirt_type_group = {
|
|
|
+ .name = VFIO_AP_MDEV_TYPE_HWVIRT,
|
|
|
+ .attrs = vfio_ap_mdev_type_attrs,
|
|
|
+};
|
|
|
+
|
|
|
+static struct attribute_group *vfio_ap_mdev_type_groups[] = {
|
|
|
+ &vfio_ap_mdev_hwvirt_type_group,
|
|
|
+ NULL,
|
|
|
+};
|
|
|
+
|
|
|
+static const struct mdev_parent_ops vfio_ap_matrix_ops = {
|
|
|
+ .owner = THIS_MODULE,
|
|
|
+ .supported_type_groups = vfio_ap_mdev_type_groups,
|
|
|
+ .create = vfio_ap_mdev_create,
|
|
|
+ .remove = vfio_ap_mdev_remove,
|
|
|
+};
|
|
|
+
|
|
|
+int vfio_ap_mdev_register(void)
|
|
|
+{
|
|
|
+ atomic_set(&matrix_dev->available_instances, MAX_ZDEV_ENTRIES_EXT);
|
|
|
+
|
|
|
+ return mdev_register_device(&matrix_dev->device, &vfio_ap_matrix_ops);
|
|
|
+}
|
|
|
+
|
|
|
+void vfio_ap_mdev_unregister(void)
|
|
|
+{
|
|
|
+ mdev_unregister_device(&matrix_dev->device);
|
|
|
+}
|