127 lines
3.1 KiB
C
127 lines
3.1 KiB
C
![]() |
// 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);
|
||
|
}
|