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_platform_common.c (17178B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2013 - Virtual Open Systems
      4 * Author: Antonios Motakis <a.motakis@virtualopensystems.com>
      5 */
      6
      7#define dev_fmt(fmt)	"VFIO: " fmt
      8
      9#include <linux/device.h>
     10#include <linux/acpi.h>
     11#include <linux/iommu.h>
     12#include <linux/module.h>
     13#include <linux/mutex.h>
     14#include <linux/pm_runtime.h>
     15#include <linux/slab.h>
     16#include <linux/types.h>
     17#include <linux/uaccess.h>
     18#include <linux/vfio.h>
     19
     20#include "vfio_platform_private.h"
     21
     22#define DRIVER_VERSION  "0.10"
     23#define DRIVER_AUTHOR   "Antonios Motakis <a.motakis@virtualopensystems.com>"
     24#define DRIVER_DESC     "VFIO platform base module"
     25
     26#define VFIO_PLATFORM_IS_ACPI(vdev) ((vdev)->acpihid != NULL)
     27
     28static LIST_HEAD(reset_list);
     29static DEFINE_MUTEX(driver_lock);
     30
     31static vfio_platform_reset_fn_t vfio_platform_lookup_reset(const char *compat,
     32					struct module **module)
     33{
     34	struct vfio_platform_reset_node *iter;
     35	vfio_platform_reset_fn_t reset_fn = NULL;
     36
     37	mutex_lock(&driver_lock);
     38	list_for_each_entry(iter, &reset_list, link) {
     39		if (!strcmp(iter->compat, compat) &&
     40			try_module_get(iter->owner)) {
     41			*module = iter->owner;
     42			reset_fn = iter->of_reset;
     43			break;
     44		}
     45	}
     46	mutex_unlock(&driver_lock);
     47	return reset_fn;
     48}
     49
     50static int vfio_platform_acpi_probe(struct vfio_platform_device *vdev,
     51				    struct device *dev)
     52{
     53	struct acpi_device *adev;
     54
     55	if (acpi_disabled)
     56		return -ENOENT;
     57
     58	adev = ACPI_COMPANION(dev);
     59	if (!adev) {
     60		dev_err(dev, "ACPI companion device not found for %s\n",
     61			vdev->name);
     62		return -ENODEV;
     63	}
     64
     65#ifdef CONFIG_ACPI
     66	vdev->acpihid = acpi_device_hid(adev);
     67#endif
     68	return WARN_ON(!vdev->acpihid) ? -EINVAL : 0;
     69}
     70
     71static int vfio_platform_acpi_call_reset(struct vfio_platform_device *vdev,
     72				  const char **extra_dbg)
     73{
     74#ifdef CONFIG_ACPI
     75	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
     76	struct device *dev = vdev->device;
     77	acpi_handle handle = ACPI_HANDLE(dev);
     78	acpi_status acpi_ret;
     79
     80	acpi_ret = acpi_evaluate_object(handle, "_RST", NULL, &buffer);
     81	if (ACPI_FAILURE(acpi_ret)) {
     82		if (extra_dbg)
     83			*extra_dbg = acpi_format_exception(acpi_ret);
     84		return -EINVAL;
     85	}
     86
     87	return 0;
     88#else
     89	return -ENOENT;
     90#endif
     91}
     92
     93static bool vfio_platform_acpi_has_reset(struct vfio_platform_device *vdev)
     94{
     95#ifdef CONFIG_ACPI
     96	struct device *dev = vdev->device;
     97	acpi_handle handle = ACPI_HANDLE(dev);
     98
     99	return acpi_has_method(handle, "_RST");
    100#else
    101	return false;
    102#endif
    103}
    104
    105static bool vfio_platform_has_reset(struct vfio_platform_device *vdev)
    106{
    107	if (VFIO_PLATFORM_IS_ACPI(vdev))
    108		return vfio_platform_acpi_has_reset(vdev);
    109
    110	return vdev->of_reset ? true : false;
    111}
    112
    113static int vfio_platform_get_reset(struct vfio_platform_device *vdev)
    114{
    115	if (VFIO_PLATFORM_IS_ACPI(vdev))
    116		return vfio_platform_acpi_has_reset(vdev) ? 0 : -ENOENT;
    117
    118	vdev->of_reset = vfio_platform_lookup_reset(vdev->compat,
    119						    &vdev->reset_module);
    120	if (!vdev->of_reset) {
    121		request_module("vfio-reset:%s", vdev->compat);
    122		vdev->of_reset = vfio_platform_lookup_reset(vdev->compat,
    123							&vdev->reset_module);
    124	}
    125
    126	return vdev->of_reset ? 0 : -ENOENT;
    127}
    128
    129static void vfio_platform_put_reset(struct vfio_platform_device *vdev)
    130{
    131	if (VFIO_PLATFORM_IS_ACPI(vdev))
    132		return;
    133
    134	if (vdev->of_reset)
    135		module_put(vdev->reset_module);
    136}
    137
    138static int vfio_platform_regions_init(struct vfio_platform_device *vdev)
    139{
    140	int cnt = 0, i;
    141
    142	while (vdev->get_resource(vdev, cnt))
    143		cnt++;
    144
    145	vdev->regions = kcalloc(cnt, sizeof(struct vfio_platform_region),
    146				GFP_KERNEL);
    147	if (!vdev->regions)
    148		return -ENOMEM;
    149
    150	for (i = 0; i < cnt;  i++) {
    151		struct resource *res =
    152			vdev->get_resource(vdev, i);
    153
    154		if (!res)
    155			goto err;
    156
    157		vdev->regions[i].addr = res->start;
    158		vdev->regions[i].size = resource_size(res);
    159		vdev->regions[i].flags = 0;
    160
    161		switch (resource_type(res)) {
    162		case IORESOURCE_MEM:
    163			vdev->regions[i].type = VFIO_PLATFORM_REGION_TYPE_MMIO;
    164			vdev->regions[i].flags |= VFIO_REGION_INFO_FLAG_READ;
    165			if (!(res->flags & IORESOURCE_READONLY))
    166				vdev->regions[i].flags |=
    167					VFIO_REGION_INFO_FLAG_WRITE;
    168
    169			/*
    170			 * Only regions addressed with PAGE granularity may be
    171			 * MMAPed securely.
    172			 */
    173			if (!(vdev->regions[i].addr & ~PAGE_MASK) &&
    174					!(vdev->regions[i].size & ~PAGE_MASK))
    175				vdev->regions[i].flags |=
    176					VFIO_REGION_INFO_FLAG_MMAP;
    177
    178			break;
    179		case IORESOURCE_IO:
    180			vdev->regions[i].type = VFIO_PLATFORM_REGION_TYPE_PIO;
    181			break;
    182		default:
    183			goto err;
    184		}
    185	}
    186
    187	vdev->num_regions = cnt;
    188
    189	return 0;
    190err:
    191	kfree(vdev->regions);
    192	return -EINVAL;
    193}
    194
    195static void vfio_platform_regions_cleanup(struct vfio_platform_device *vdev)
    196{
    197	int i;
    198
    199	for (i = 0; i < vdev->num_regions; i++)
    200		iounmap(vdev->regions[i].ioaddr);
    201
    202	vdev->num_regions = 0;
    203	kfree(vdev->regions);
    204}
    205
    206static int vfio_platform_call_reset(struct vfio_platform_device *vdev,
    207				    const char **extra_dbg)
    208{
    209	if (VFIO_PLATFORM_IS_ACPI(vdev)) {
    210		dev_info(vdev->device, "reset\n");
    211		return vfio_platform_acpi_call_reset(vdev, extra_dbg);
    212	} else if (vdev->of_reset) {
    213		dev_info(vdev->device, "reset\n");
    214		return vdev->of_reset(vdev);
    215	}
    216
    217	dev_warn(vdev->device, "no reset function found!\n");
    218	return -EINVAL;
    219}
    220
    221static void vfio_platform_close_device(struct vfio_device *core_vdev)
    222{
    223	struct vfio_platform_device *vdev =
    224		container_of(core_vdev, struct vfio_platform_device, vdev);
    225	const char *extra_dbg = NULL;
    226	int ret;
    227
    228	ret = vfio_platform_call_reset(vdev, &extra_dbg);
    229	if (WARN_ON(ret && vdev->reset_required)) {
    230		dev_warn(
    231			vdev->device,
    232			"reset driver is required and reset call failed in release (%d) %s\n",
    233			ret, extra_dbg ? extra_dbg : "");
    234	}
    235	pm_runtime_put(vdev->device);
    236	vfio_platform_regions_cleanup(vdev);
    237	vfio_platform_irq_cleanup(vdev);
    238}
    239
    240static int vfio_platform_open_device(struct vfio_device *core_vdev)
    241{
    242	struct vfio_platform_device *vdev =
    243		container_of(core_vdev, struct vfio_platform_device, vdev);
    244	const char *extra_dbg = NULL;
    245	int ret;
    246
    247	ret = vfio_platform_regions_init(vdev);
    248	if (ret)
    249		return ret;
    250
    251	ret = vfio_platform_irq_init(vdev);
    252	if (ret)
    253		goto err_irq;
    254
    255	ret = pm_runtime_get_sync(vdev->device);
    256	if (ret < 0)
    257		goto err_rst;
    258
    259	ret = vfio_platform_call_reset(vdev, &extra_dbg);
    260	if (ret && vdev->reset_required) {
    261		dev_warn(
    262			vdev->device,
    263			"reset driver is required and reset call failed in open (%d) %s\n",
    264			ret, extra_dbg ? extra_dbg : "");
    265		goto err_rst;
    266	}
    267	return 0;
    268
    269err_rst:
    270	pm_runtime_put(vdev->device);
    271	vfio_platform_irq_cleanup(vdev);
    272err_irq:
    273	vfio_platform_regions_cleanup(vdev);
    274	return ret;
    275}
    276
    277static long vfio_platform_ioctl(struct vfio_device *core_vdev,
    278				unsigned int cmd, unsigned long arg)
    279{
    280	struct vfio_platform_device *vdev =
    281		container_of(core_vdev, struct vfio_platform_device, vdev);
    282
    283	unsigned long minsz;
    284
    285	if (cmd == VFIO_DEVICE_GET_INFO) {
    286		struct vfio_device_info info;
    287
    288		minsz = offsetofend(struct vfio_device_info, num_irqs);
    289
    290		if (copy_from_user(&info, (void __user *)arg, minsz))
    291			return -EFAULT;
    292
    293		if (info.argsz < minsz)
    294			return -EINVAL;
    295
    296		if (vfio_platform_has_reset(vdev))
    297			vdev->flags |= VFIO_DEVICE_FLAGS_RESET;
    298		info.flags = vdev->flags;
    299		info.num_regions = vdev->num_regions;
    300		info.num_irqs = vdev->num_irqs;
    301
    302		return copy_to_user((void __user *)arg, &info, minsz) ?
    303			-EFAULT : 0;
    304
    305	} else if (cmd == VFIO_DEVICE_GET_REGION_INFO) {
    306		struct vfio_region_info info;
    307
    308		minsz = offsetofend(struct vfio_region_info, offset);
    309
    310		if (copy_from_user(&info, (void __user *)arg, minsz))
    311			return -EFAULT;
    312
    313		if (info.argsz < minsz)
    314			return -EINVAL;
    315
    316		if (info.index >= vdev->num_regions)
    317			return -EINVAL;
    318
    319		/* map offset to the physical address  */
    320		info.offset = VFIO_PLATFORM_INDEX_TO_OFFSET(info.index);
    321		info.size = vdev->regions[info.index].size;
    322		info.flags = vdev->regions[info.index].flags;
    323
    324		return copy_to_user((void __user *)arg, &info, minsz) ?
    325			-EFAULT : 0;
    326
    327	} else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) {
    328		struct vfio_irq_info info;
    329
    330		minsz = offsetofend(struct vfio_irq_info, count);
    331
    332		if (copy_from_user(&info, (void __user *)arg, minsz))
    333			return -EFAULT;
    334
    335		if (info.argsz < minsz)
    336			return -EINVAL;
    337
    338		if (info.index >= vdev->num_irqs)
    339			return -EINVAL;
    340
    341		info.flags = vdev->irqs[info.index].flags;
    342		info.count = vdev->irqs[info.index].count;
    343
    344		return copy_to_user((void __user *)arg, &info, minsz) ?
    345			-EFAULT : 0;
    346
    347	} else if (cmd == VFIO_DEVICE_SET_IRQS) {
    348		struct vfio_irq_set hdr;
    349		u8 *data = NULL;
    350		int ret = 0;
    351		size_t data_size = 0;
    352
    353		minsz = offsetofend(struct vfio_irq_set, count);
    354
    355		if (copy_from_user(&hdr, (void __user *)arg, minsz))
    356			return -EFAULT;
    357
    358		ret = vfio_set_irqs_validate_and_prepare(&hdr, vdev->num_irqs,
    359						 vdev->num_irqs, &data_size);
    360		if (ret)
    361			return ret;
    362
    363		if (data_size) {
    364			data = memdup_user((void __user *)(arg + minsz),
    365					    data_size);
    366			if (IS_ERR(data))
    367				return PTR_ERR(data);
    368		}
    369
    370		mutex_lock(&vdev->igate);
    371
    372		ret = vfio_platform_set_irqs_ioctl(vdev, hdr.flags, hdr.index,
    373						   hdr.start, hdr.count, data);
    374		mutex_unlock(&vdev->igate);
    375		kfree(data);
    376
    377		return ret;
    378
    379	} else if (cmd == VFIO_DEVICE_RESET) {
    380		return vfio_platform_call_reset(vdev, NULL);
    381	}
    382
    383	return -ENOTTY;
    384}
    385
    386static ssize_t vfio_platform_read_mmio(struct vfio_platform_region *reg,
    387				       char __user *buf, size_t count,
    388				       loff_t off)
    389{
    390	unsigned int done = 0;
    391
    392	if (!reg->ioaddr) {
    393		reg->ioaddr =
    394			ioremap(reg->addr, reg->size);
    395
    396		if (!reg->ioaddr)
    397			return -ENOMEM;
    398	}
    399
    400	while (count) {
    401		size_t filled;
    402
    403		if (count >= 4 && !(off % 4)) {
    404			u32 val;
    405
    406			val = ioread32(reg->ioaddr + off);
    407			if (copy_to_user(buf, &val, 4))
    408				goto err;
    409
    410			filled = 4;
    411		} else if (count >= 2 && !(off % 2)) {
    412			u16 val;
    413
    414			val = ioread16(reg->ioaddr + off);
    415			if (copy_to_user(buf, &val, 2))
    416				goto err;
    417
    418			filled = 2;
    419		} else {
    420			u8 val;
    421
    422			val = ioread8(reg->ioaddr + off);
    423			if (copy_to_user(buf, &val, 1))
    424				goto err;
    425
    426			filled = 1;
    427		}
    428
    429
    430		count -= filled;
    431		done += filled;
    432		off += filled;
    433		buf += filled;
    434	}
    435
    436	return done;
    437err:
    438	return -EFAULT;
    439}
    440
    441static ssize_t vfio_platform_read(struct vfio_device *core_vdev,
    442				  char __user *buf, size_t count, loff_t *ppos)
    443{
    444	struct vfio_platform_device *vdev =
    445		container_of(core_vdev, struct vfio_platform_device, vdev);
    446	unsigned int index = VFIO_PLATFORM_OFFSET_TO_INDEX(*ppos);
    447	loff_t off = *ppos & VFIO_PLATFORM_OFFSET_MASK;
    448
    449	if (index >= vdev->num_regions)
    450		return -EINVAL;
    451
    452	if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_READ))
    453		return -EINVAL;
    454
    455	if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_MMIO)
    456		return vfio_platform_read_mmio(&vdev->regions[index],
    457							buf, count, off);
    458	else if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_PIO)
    459		return -EINVAL; /* not implemented */
    460
    461	return -EINVAL;
    462}
    463
    464static ssize_t vfio_platform_write_mmio(struct vfio_platform_region *reg,
    465					const char __user *buf, size_t count,
    466					loff_t off)
    467{
    468	unsigned int done = 0;
    469
    470	if (!reg->ioaddr) {
    471		reg->ioaddr =
    472			ioremap(reg->addr, reg->size);
    473
    474		if (!reg->ioaddr)
    475			return -ENOMEM;
    476	}
    477
    478	while (count) {
    479		size_t filled;
    480
    481		if (count >= 4 && !(off % 4)) {
    482			u32 val;
    483
    484			if (copy_from_user(&val, buf, 4))
    485				goto err;
    486			iowrite32(val, reg->ioaddr + off);
    487
    488			filled = 4;
    489		} else if (count >= 2 && !(off % 2)) {
    490			u16 val;
    491
    492			if (copy_from_user(&val, buf, 2))
    493				goto err;
    494			iowrite16(val, reg->ioaddr + off);
    495
    496			filled = 2;
    497		} else {
    498			u8 val;
    499
    500			if (copy_from_user(&val, buf, 1))
    501				goto err;
    502			iowrite8(val, reg->ioaddr + off);
    503
    504			filled = 1;
    505		}
    506
    507		count -= filled;
    508		done += filled;
    509		off += filled;
    510		buf += filled;
    511	}
    512
    513	return done;
    514err:
    515	return -EFAULT;
    516}
    517
    518static ssize_t vfio_platform_write(struct vfio_device *core_vdev, const char __user *buf,
    519				   size_t count, loff_t *ppos)
    520{
    521	struct vfio_platform_device *vdev =
    522		container_of(core_vdev, struct vfio_platform_device, vdev);
    523	unsigned int index = VFIO_PLATFORM_OFFSET_TO_INDEX(*ppos);
    524	loff_t off = *ppos & VFIO_PLATFORM_OFFSET_MASK;
    525
    526	if (index >= vdev->num_regions)
    527		return -EINVAL;
    528
    529	if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_WRITE))
    530		return -EINVAL;
    531
    532	if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_MMIO)
    533		return vfio_platform_write_mmio(&vdev->regions[index],
    534							buf, count, off);
    535	else if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_PIO)
    536		return -EINVAL; /* not implemented */
    537
    538	return -EINVAL;
    539}
    540
    541static int vfio_platform_mmap_mmio(struct vfio_platform_region region,
    542				   struct vm_area_struct *vma)
    543{
    544	u64 req_len, pgoff, req_start;
    545
    546	req_len = vma->vm_end - vma->vm_start;
    547	pgoff = vma->vm_pgoff &
    548		((1U << (VFIO_PLATFORM_OFFSET_SHIFT - PAGE_SHIFT)) - 1);
    549	req_start = pgoff << PAGE_SHIFT;
    550
    551	if (region.size < PAGE_SIZE || req_start + req_len > region.size)
    552		return -EINVAL;
    553
    554	vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
    555	vma->vm_pgoff = (region.addr >> PAGE_SHIFT) + pgoff;
    556
    557	return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
    558			       req_len, vma->vm_page_prot);
    559}
    560
    561static int vfio_platform_mmap(struct vfio_device *core_vdev, struct vm_area_struct *vma)
    562{
    563	struct vfio_platform_device *vdev =
    564		container_of(core_vdev, struct vfio_platform_device, vdev);
    565	unsigned int index;
    566
    567	index = vma->vm_pgoff >> (VFIO_PLATFORM_OFFSET_SHIFT - PAGE_SHIFT);
    568
    569	if (vma->vm_end < vma->vm_start)
    570		return -EINVAL;
    571	if (!(vma->vm_flags & VM_SHARED))
    572		return -EINVAL;
    573	if (index >= vdev->num_regions)
    574		return -EINVAL;
    575	if (vma->vm_start & ~PAGE_MASK)
    576		return -EINVAL;
    577	if (vma->vm_end & ~PAGE_MASK)
    578		return -EINVAL;
    579
    580	if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_MMAP))
    581		return -EINVAL;
    582
    583	if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_READ)
    584			&& (vma->vm_flags & VM_READ))
    585		return -EINVAL;
    586
    587	if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_WRITE)
    588			&& (vma->vm_flags & VM_WRITE))
    589		return -EINVAL;
    590
    591	vma->vm_private_data = vdev;
    592
    593	if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_MMIO)
    594		return vfio_platform_mmap_mmio(vdev->regions[index], vma);
    595
    596	else if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_PIO)
    597		return -EINVAL; /* not implemented */
    598
    599	return -EINVAL;
    600}
    601
    602static const struct vfio_device_ops vfio_platform_ops = {
    603	.name		= "vfio-platform",
    604	.open_device	= vfio_platform_open_device,
    605	.close_device	= vfio_platform_close_device,
    606	.ioctl		= vfio_platform_ioctl,
    607	.read		= vfio_platform_read,
    608	.write		= vfio_platform_write,
    609	.mmap		= vfio_platform_mmap,
    610};
    611
    612static int vfio_platform_of_probe(struct vfio_platform_device *vdev,
    613			   struct device *dev)
    614{
    615	int ret;
    616
    617	ret = device_property_read_string(dev, "compatible",
    618					  &vdev->compat);
    619	if (ret)
    620		dev_err(dev, "Cannot retrieve compat for %s\n", vdev->name);
    621
    622	return ret;
    623}
    624
    625/*
    626 * There can be two kernel build combinations. One build where
    627 * ACPI is not selected in Kconfig and another one with the ACPI Kconfig.
    628 *
    629 * In the first case, vfio_platform_acpi_probe will return since
    630 * acpi_disabled is 1. DT user will not see any kind of messages from
    631 * ACPI.
    632 *
    633 * In the second case, both DT and ACPI is compiled in but the system is
    634 * booting with any of these combinations.
    635 *
    636 * If the firmware is DT type, then acpi_disabled is 1. The ACPI probe routine
    637 * terminates immediately without any messages.
    638 *
    639 * If the firmware is ACPI type, then acpi_disabled is 0. All other checks are
    640 * valid checks. We cannot claim that this system is DT.
    641 */
    642int vfio_platform_probe_common(struct vfio_platform_device *vdev,
    643			       struct device *dev)
    644{
    645	int ret;
    646
    647	vfio_init_group_dev(&vdev->vdev, dev, &vfio_platform_ops);
    648
    649	ret = vfio_platform_acpi_probe(vdev, dev);
    650	if (ret)
    651		ret = vfio_platform_of_probe(vdev, dev);
    652
    653	if (ret)
    654		goto out_uninit;
    655
    656	vdev->device = dev;
    657
    658	ret = vfio_platform_get_reset(vdev);
    659	if (ret && vdev->reset_required) {
    660		dev_err(dev, "No reset function found for device %s\n",
    661			vdev->name);
    662		goto out_uninit;
    663	}
    664
    665	ret = vfio_register_group_dev(&vdev->vdev);
    666	if (ret)
    667		goto put_reset;
    668
    669	mutex_init(&vdev->igate);
    670
    671	pm_runtime_enable(dev);
    672	return 0;
    673
    674put_reset:
    675	vfio_platform_put_reset(vdev);
    676out_uninit:
    677	vfio_uninit_group_dev(&vdev->vdev);
    678	return ret;
    679}
    680EXPORT_SYMBOL_GPL(vfio_platform_probe_common);
    681
    682void vfio_platform_remove_common(struct vfio_platform_device *vdev)
    683{
    684	vfio_unregister_group_dev(&vdev->vdev);
    685
    686	pm_runtime_disable(vdev->device);
    687	vfio_platform_put_reset(vdev);
    688	vfio_uninit_group_dev(&vdev->vdev);
    689}
    690EXPORT_SYMBOL_GPL(vfio_platform_remove_common);
    691
    692void __vfio_platform_register_reset(struct vfio_platform_reset_node *node)
    693{
    694	mutex_lock(&driver_lock);
    695	list_add(&node->link, &reset_list);
    696	mutex_unlock(&driver_lock);
    697}
    698EXPORT_SYMBOL_GPL(__vfio_platform_register_reset);
    699
    700void vfio_platform_unregister_reset(const char *compat,
    701				    vfio_platform_reset_fn_t fn)
    702{
    703	struct vfio_platform_reset_node *iter, *temp;
    704
    705	mutex_lock(&driver_lock);
    706	list_for_each_entry_safe(iter, temp, &reset_list, link) {
    707		if (!strcmp(iter->compat, compat) && (iter->of_reset == fn)) {
    708			list_del(&iter->link);
    709			break;
    710		}
    711	}
    712
    713	mutex_unlock(&driver_lock);
    714
    715}
    716EXPORT_SYMBOL_GPL(vfio_platform_unregister_reset);
    717
    718MODULE_VERSION(DRIVER_VERSION);
    719MODULE_LICENSE("GPL v2");
    720MODULE_AUTHOR(DRIVER_AUTHOR);
    721MODULE_DESCRIPTION(DRIVER_DESC);