brintos

brintos / linux-shallow public Read only

0
0
Text · 4.8 KiB · 67a807e Raw
210 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * VFIO based AP device driver4 *5 * Copyright IBM Corp. 20186 *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 22MODULE_AUTHOR("IBM Corporation");23MODULE_DESCRIPTION("VFIO AP device driver, Copyright IBM Corp. 2018");24MODULE_LICENSE("GPL v2");25 26struct ap_matrix_dev *matrix_dev;27debug_info_t *vfio_ap_dbf_info;28 29static ssize_t features_show(struct device *dev, struct device_attribute *attr, char *buf)30{31	return sysfs_emit(buf, "guest_matrix hotplug ap_config\n");32}33static DEVICE_ATTR_RO(features);34 35static struct attribute *matrix_dev_attrs[] = {36	&dev_attr_features.attr,37	NULL,38};39ATTRIBUTE_GROUPS(matrix_dev);40 41/* Only type 10 adapters (CEX4 and later) are supported42 * by the AP matrix device driver43 */44static struct ap_device_id ap_queue_ids[] = {45	{ .dev_type = AP_DEVICE_TYPE_CEX4,46	  .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },47	{ .dev_type = AP_DEVICE_TYPE_CEX5,48	  .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },49	{ .dev_type = AP_DEVICE_TYPE_CEX6,50	  .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },51	{ .dev_type = AP_DEVICE_TYPE_CEX7,52	  .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },53	{ .dev_type = AP_DEVICE_TYPE_CEX8,54	  .match_flags = AP_DEVICE_ID_MATCH_QUEUE_TYPE },55	{ /* end of sibling */ },56};57 58static struct ap_driver vfio_ap_drv = {59	.probe = vfio_ap_mdev_probe_queue,60	.remove = vfio_ap_mdev_remove_queue,61	.in_use = vfio_ap_mdev_resource_in_use,62	.on_config_changed = vfio_ap_on_cfg_changed,63	.on_scan_complete = vfio_ap_on_scan_complete,64	.ids = ap_queue_ids,65};66 67static void vfio_ap_matrix_dev_release(struct device *dev)68{69	struct ap_matrix_dev *matrix_dev;70 71	matrix_dev = container_of(dev, struct ap_matrix_dev, device);72	kfree(matrix_dev);73}74 75static const struct bus_type matrix_bus = {76	.name = "matrix",77};78 79static struct device_driver matrix_driver = {80	.name = "vfio_ap",81	.bus = &matrix_bus,82	.suppress_bind_attrs = true,83	.dev_groups = matrix_dev_groups,84};85 86static int vfio_ap_matrix_dev_create(void)87{88	int ret;89	struct device *root_device;90 91	root_device = root_device_register(VFIO_AP_ROOT_NAME);92	if (IS_ERR(root_device))93		return PTR_ERR(root_device);94 95	ret = bus_register(&matrix_bus);96	if (ret)97		goto bus_register_err;98 99	matrix_dev = kzalloc(sizeof(*matrix_dev), GFP_KERNEL);100	if (!matrix_dev) {101		ret = -ENOMEM;102		goto matrix_alloc_err;103	}104 105	/* Fill in config info via PQAP(QCI), if available */106	if (test_facility(12)) {107		ret = ap_qci(&matrix_dev->info);108		if (ret)109			goto matrix_alloc_err;110	}111 112	mutex_init(&matrix_dev->mdevs_lock);113	INIT_LIST_HEAD(&matrix_dev->mdev_list);114	mutex_init(&matrix_dev->guests_lock);115 116	dev_set_name(&matrix_dev->device, "%s", VFIO_AP_DEV_NAME);117	matrix_dev->device.parent = root_device;118	matrix_dev->device.bus = &matrix_bus;119	matrix_dev->device.release = vfio_ap_matrix_dev_release;120	matrix_dev->vfio_ap_drv = &vfio_ap_drv;121 122	ret = device_register(&matrix_dev->device);123	if (ret)124		goto matrix_reg_err;125 126	ret = driver_register(&matrix_driver);127	if (ret)128		goto matrix_drv_err;129 130	return 0;131 132matrix_drv_err:133	device_del(&matrix_dev->device);134matrix_reg_err:135	put_device(&matrix_dev->device);136matrix_alloc_err:137	bus_unregister(&matrix_bus);138bus_register_err:139	root_device_unregister(root_device);140	return ret;141}142 143static void vfio_ap_matrix_dev_destroy(void)144{145	struct device *root_device = matrix_dev->device.parent;146 147	driver_unregister(&matrix_driver);148	device_unregister(&matrix_dev->device);149	bus_unregister(&matrix_bus);150	root_device_unregister(root_device);151}152 153static int __init vfio_ap_dbf_info_init(void)154{155	vfio_ap_dbf_info = debug_register("vfio_ap", 1, 1,156					  DBF_MAX_SPRINTF_ARGS * sizeof(long));157 158	if (!vfio_ap_dbf_info)159		return -ENOENT;160 161	debug_register_view(vfio_ap_dbf_info, &debug_sprintf_view);162	debug_set_level(vfio_ap_dbf_info, DBF_WARN);163 164	return 0;165}166 167static int __init vfio_ap_init(void)168{169	int ret;170 171	ret = vfio_ap_dbf_info_init();172	if (ret)173		return ret;174 175	/* If there are no AP instructions, there is nothing to pass through. */176	if (!ap_instructions_available())177		return -ENODEV;178 179	ret = vfio_ap_matrix_dev_create();180	if (ret)181		return ret;182 183	ret = ap_driver_register(&vfio_ap_drv, THIS_MODULE, VFIO_AP_DRV_NAME);184	if (ret) {185		vfio_ap_matrix_dev_destroy();186		return ret;187	}188 189	ret = vfio_ap_mdev_register();190	if (ret) {191		ap_driver_unregister(&vfio_ap_drv);192		vfio_ap_matrix_dev_destroy();193 194		return ret;195	}196 197	return 0;198}199 200static void __exit vfio_ap_exit(void)201{202	vfio_ap_mdev_unregister();203	ap_driver_unregister(&vfio_ap_drv);204	vfio_ap_matrix_dev_destroy();205	debug_unregister(vfio_ap_dbf_info);206}207 208module_init(vfio_ap_init);209module_exit(vfio_ap_exit);210