cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vfio_ap_drv.c (7369B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * VFIO based AP device driver
      4 *
      5 * Copyright IBM Corp. 2018
      6 *
      7 * Author(s): Tony Krowiak <akrowiak@linux.ibm.com>
      8 *	      Pierre Morel <pmorel@linux.ibm.com>
      9 */
     10
     11#include <linux/module.h>
     12#include <linux/mod_devicetable.h>
     13#include <linux/slab.h>
     14#include <linux/string.h>
     15#include <asm/facility.h>
     16#include "vfio_ap_private.h"
     17#include "vfio_ap_debug.h"
     18
     19#define VFIO_AP_ROOT_NAME "vfio_ap"
     20#define VFIO_AP_DEV_NAME "matrix"
     21#define AP_QUEUE_ASSIGNED "assigned"
     22#define AP_QUEUE_UNASSIGNED "unassigned"
     23#define AP_QUEUE_IN_USE "in use"
     24
     25MODULE_AUTHOR("IBM Corporation");
     26MODULE_DESCRIPTION("VFIO AP device driver, Copyright IBM Corp. 2018");
     27MODULE_LICENSE("GPL v2");
     28
     29struct ap_matrix_dev *matrix_dev;
     30debug_info_t *vfio_ap_dbf_info;
     31
     32/* Only type 10 adapters (CEX4 and later) are supported
     33 * by the AP matrix device driver
     34 */
     35static struct ap_device_id ap_queue_ids[] = {
     36	{ .dev_type = AP_DEVICE_TYPE_CEX4,
     37	  .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
     38	{ .dev_type = AP_DEVICE_TYPE_CEX5,
     39	  .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
     40	{ .dev_type = AP_DEVICE_TYPE_CEX6,
     41	  .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
     42	{ .dev_type = AP_DEVICE_TYPE_CEX7,
     43	  .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
     44	{ .dev_type = AP_DEVICE_TYPE_CEX8,
     45	  .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },
     46	{ /* end of sibling */ },
     47};
     48
     49static struct ap_matrix_mdev *vfio_ap_mdev_for_queue(struct vfio_ap_queue *q)
     50{
     51	struct ap_matrix_mdev *matrix_mdev;
     52	unsigned long apid = AP_QID_CARD(q->apqn);
     53	unsigned long apqi = AP_QID_QUEUE(q->apqn);
     54
     55	list_for_each_entry(matrix_mdev, &matrix_dev->mdev_list, node) {
     56		if (test_bit_inv(apid, matrix_mdev->matrix.apm) &&
     57		    test_bit_inv(apqi, matrix_mdev->matrix.aqm))
     58			return matrix_mdev;
     59	}
     60
     61	return NULL;
     62}
     63
     64static ssize_t status_show(struct device *dev,
     65			   struct device_attribute *attr,
     66			   char *buf)
     67{
     68	ssize_t nchars = 0;
     69	struct vfio_ap_queue *q;
     70	struct ap_matrix_mdev *matrix_mdev;
     71	struct ap_device *apdev = to_ap_dev(dev);
     72
     73	mutex_lock(&matrix_dev->lock);
     74	q = dev_get_drvdata(&apdev->device);
     75	matrix_mdev = vfio_ap_mdev_for_queue(q);
     76
     77	if (matrix_mdev) {
     78		if (matrix_mdev->kvm)
     79			nchars = scnprintf(buf, PAGE_SIZE, "%s\n",
     80					   AP_QUEUE_IN_USE);
     81		else
     82			nchars = scnprintf(buf, PAGE_SIZE, "%s\n",
     83					   AP_QUEUE_ASSIGNED);
     84	} else {
     85		nchars = scnprintf(buf, PAGE_SIZE, "%s\n",
     86				   AP_QUEUE_UNASSIGNED);
     87	}
     88
     89	mutex_unlock(&matrix_dev->lock);
     90
     91	return nchars;
     92}
     93
     94static DEVICE_ATTR_RO(status);
     95
     96static struct attribute *vfio_queue_attrs[] = {
     97	&dev_attr_status.attr,
     98	NULL,
     99};
    100
    101static const struct attribute_group vfio_queue_attr_group = {
    102	.attrs = vfio_queue_attrs,
    103};
    104
    105/**
    106 * vfio_ap_queue_dev_probe: Allocate a vfio_ap_queue structure and associate it
    107 *			    with the device as driver_data.
    108 *
    109 * @apdev: the AP device being probed
    110 *
    111 * Return: returns 0 if the probe succeeded; otherwise, returns an error if
    112 *	   storage could not be allocated for a vfio_ap_queue object or the
    113 *	   sysfs 'status' attribute could not be created for the queue device.
    114 */
    115static int vfio_ap_queue_dev_probe(struct ap_device *apdev)
    116{
    117	int ret;
    118	struct vfio_ap_queue *q;
    119
    120	q = kzalloc(sizeof(*q), GFP_KERNEL);
    121	if (!q)
    122		return -ENOMEM;
    123
    124	mutex_lock(&matrix_dev->lock);
    125	dev_set_drvdata(&apdev->device, q);
    126	q->apqn = to_ap_queue(&apdev->device)->qid;
    127	q->saved_isc = VFIO_AP_ISC_INVALID;
    128
    129	ret = sysfs_create_group(&apdev->device.kobj, &vfio_queue_attr_group);
    130	if (ret) {
    131		dev_set_drvdata(&apdev->device, NULL);
    132		kfree(q);
    133	}
    134
    135	mutex_unlock(&matrix_dev->lock);
    136
    137	return ret;
    138}
    139
    140/**
    141 * vfio_ap_queue_dev_remove: Free the associated vfio_ap_queue structure.
    142 *
    143 * @apdev: the AP device being removed
    144 *
    145 * Takes the matrix lock to avoid actions on this device while doing the remove.
    146 */
    147static void vfio_ap_queue_dev_remove(struct ap_device *apdev)
    148{
    149	struct vfio_ap_queue *q;
    150
    151	mutex_lock(&matrix_dev->lock);
    152	sysfs_remove_group(&apdev->device.kobj, &vfio_queue_attr_group);
    153	q = dev_get_drvdata(&apdev->device);
    154	vfio_ap_mdev_reset_queue(q, 1);
    155	dev_set_drvdata(&apdev->device, NULL);
    156	kfree(q);
    157	mutex_unlock(&matrix_dev->lock);
    158}
    159
    160static struct ap_driver vfio_ap_drv = {
    161	.probe = vfio_ap_queue_dev_probe,
    162	.remove = vfio_ap_queue_dev_remove,
    163	.ids = ap_queue_ids,
    164};
    165
    166static void vfio_ap_matrix_dev_release(struct device *dev)
    167{
    168	struct ap_matrix_dev *matrix_dev = dev_get_drvdata(dev);
    169
    170	kfree(matrix_dev);
    171}
    172
    173static int matrix_bus_match(struct device *dev, struct device_driver *drv)
    174{
    175	return 1;
    176}
    177
    178static struct bus_type matrix_bus = {
    179	.name = "matrix",
    180	.match = &matrix_bus_match,
    181};
    182
    183static struct device_driver matrix_driver = {
    184	.name = "vfio_ap",
    185	.bus = &matrix_bus,
    186	.suppress_bind_attrs = true,
    187};
    188
    189static int vfio_ap_matrix_dev_create(void)
    190{
    191	int ret;
    192	struct device *root_device;
    193
    194	root_device = root_device_register(VFIO_AP_ROOT_NAME);
    195	if (IS_ERR(root_device))
    196		return PTR_ERR(root_device);
    197
    198	ret = bus_register(&matrix_bus);
    199	if (ret)
    200		goto bus_register_err;
    201
    202	matrix_dev = kzalloc(sizeof(*matrix_dev), GFP_KERNEL);
    203	if (!matrix_dev) {
    204		ret = -ENOMEM;
    205		goto matrix_alloc_err;
    206	}
    207
    208	/* Fill in config info via PQAP(QCI), if available */
    209	if (test_facility(12)) {
    210		ret = ap_qci(&matrix_dev->info);
    211		if (ret)
    212			goto matrix_alloc_err;
    213	}
    214
    215	mutex_init(&matrix_dev->lock);
    216	INIT_LIST_HEAD(&matrix_dev->mdev_list);
    217
    218	dev_set_name(&matrix_dev->device, "%s", VFIO_AP_DEV_NAME);
    219	matrix_dev->device.parent = root_device;
    220	matrix_dev->device.bus = &matrix_bus;
    221	matrix_dev->device.release = vfio_ap_matrix_dev_release;
    222	matrix_dev->vfio_ap_drv = &vfio_ap_drv;
    223
    224	ret = device_register(&matrix_dev->device);
    225	if (ret)
    226		goto matrix_reg_err;
    227
    228	ret = driver_register(&matrix_driver);
    229	if (ret)
    230		goto matrix_drv_err;
    231
    232	return 0;
    233
    234matrix_drv_err:
    235	device_unregister(&matrix_dev->device);
    236matrix_reg_err:
    237	put_device(&matrix_dev->device);
    238matrix_alloc_err:
    239	bus_unregister(&matrix_bus);
    240bus_register_err:
    241	root_device_unregister(root_device);
    242	return ret;
    243}
    244
    245static void vfio_ap_matrix_dev_destroy(void)
    246{
    247	struct device *root_device = matrix_dev->device.parent;
    248
    249	driver_unregister(&matrix_driver);
    250	device_unregister(&matrix_dev->device);
    251	bus_unregister(&matrix_bus);
    252	root_device_unregister(root_device);
    253}
    254
    255static int __init vfio_ap_dbf_info_init(void)
    256{
    257	vfio_ap_dbf_info = debug_register("vfio_ap", 1, 1,
    258					  DBF_MAX_SPRINTF_ARGS * sizeof(long));
    259
    260	if (!vfio_ap_dbf_info)
    261		return -ENOENT;
    262
    263	debug_register_view(vfio_ap_dbf_info, &debug_sprintf_view);
    264	debug_set_level(vfio_ap_dbf_info, DBF_WARN);
    265
    266	return 0;
    267}
    268
    269static int __init vfio_ap_init(void)
    270{
    271	int ret;
    272
    273	ret = vfio_ap_dbf_info_init();
    274	if (ret)
    275		return ret;
    276
    277	/* If there are no AP instructions, there is nothing to pass through. */
    278	if (!ap_instructions_available())
    279		return -ENODEV;
    280
    281	ret = vfio_ap_matrix_dev_create();
    282	if (ret)
    283		return ret;
    284
    285	ret = ap_driver_register(&vfio_ap_drv, THIS_MODULE, VFIO_AP_DRV_NAME);
    286	if (ret) {
    287		vfio_ap_matrix_dev_destroy();
    288		return ret;
    289	}
    290
    291	ret = vfio_ap_mdev_register();
    292	if (ret) {
    293		ap_driver_unregister(&vfio_ap_drv);
    294		vfio_ap_matrix_dev_destroy();
    295
    296		return ret;
    297	}
    298
    299	return 0;
    300}
    301
    302static void __exit vfio_ap_exit(void)
    303{
    304	vfio_ap_mdev_unregister();
    305	ap_driver_unregister(&vfio_ap_drv);
    306	vfio_ap_matrix_dev_destroy();
    307	debug_unregister(vfio_ap_dbf_info);
    308}
    309
    310module_init(vfio_ap_init);
    311module_exit(vfio_ap_exit);