Merge branch 'next' into for-linus
[linux-2.6-microblaze.git] / drivers / vfio / platform / vfio_platform_common.c
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
28 static LIST_HEAD(reset_list);
29 static DEFINE_MUTEX(driver_lock);
30
31 static 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
50 static 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
71 static 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
93 static 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
105 static 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
113 static 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
129 static 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
138 static 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;
190 err:
191         kfree(vdev->regions);
192         return -EINVAL;
193 }
194
195 static 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
206 static 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
221 static void vfio_platform_release(void *device_data)
222 {
223         struct vfio_platform_device *vdev = device_data;
224
225         mutex_lock(&driver_lock);
226
227         if (!(--vdev->refcnt)) {
228                 const char *extra_dbg = NULL;
229                 int ret;
230
231                 ret = vfio_platform_call_reset(vdev, &extra_dbg);
232                 if (ret && vdev->reset_required) {
233                         dev_warn(vdev->device, "reset driver is required and reset call failed in release (%d) %s\n",
234                                  ret, extra_dbg ? extra_dbg : "");
235                         WARN_ON(1);
236                 }
237                 pm_runtime_put(vdev->device);
238                 vfio_platform_regions_cleanup(vdev);
239                 vfio_platform_irq_cleanup(vdev);
240         }
241
242         mutex_unlock(&driver_lock);
243
244         module_put(vdev->parent_module);
245 }
246
247 static int vfio_platform_open(void *device_data)
248 {
249         struct vfio_platform_device *vdev = device_data;
250         int ret;
251
252         if (!try_module_get(vdev->parent_module))
253                 return -ENODEV;
254
255         mutex_lock(&driver_lock);
256
257         if (!vdev->refcnt) {
258                 const char *extra_dbg = NULL;
259
260                 ret = vfio_platform_regions_init(vdev);
261                 if (ret)
262                         goto err_reg;
263
264                 ret = vfio_platform_irq_init(vdev);
265                 if (ret)
266                         goto err_irq;
267
268                 ret = pm_runtime_get_sync(vdev->device);
269                 if (ret < 0)
270                         goto err_rst;
271
272                 ret = vfio_platform_call_reset(vdev, &extra_dbg);
273                 if (ret && vdev->reset_required) {
274                         dev_warn(vdev->device, "reset driver is required and reset call failed in open (%d) %s\n",
275                                  ret, extra_dbg ? extra_dbg : "");
276                         goto err_rst;
277                 }
278         }
279
280         vdev->refcnt++;
281
282         mutex_unlock(&driver_lock);
283         return 0;
284
285 err_rst:
286         pm_runtime_put(vdev->device);
287         vfio_platform_irq_cleanup(vdev);
288 err_irq:
289         vfio_platform_regions_cleanup(vdev);
290 err_reg:
291         mutex_unlock(&driver_lock);
292         module_put(THIS_MODULE);
293         return ret;
294 }
295
296 static long vfio_platform_ioctl(void *device_data,
297                                 unsigned int cmd, unsigned long arg)
298 {
299         struct vfio_platform_device *vdev = device_data;
300         unsigned long minsz;
301
302         if (cmd == VFIO_DEVICE_GET_INFO) {
303                 struct vfio_device_info info;
304
305                 minsz = offsetofend(struct vfio_device_info, num_irqs);
306
307                 if (copy_from_user(&info, (void __user *)arg, minsz))
308                         return -EFAULT;
309
310                 if (info.argsz < minsz)
311                         return -EINVAL;
312
313                 if (vfio_platform_has_reset(vdev))
314                         vdev->flags |= VFIO_DEVICE_FLAGS_RESET;
315                 info.flags = vdev->flags;
316                 info.num_regions = vdev->num_regions;
317                 info.num_irqs = vdev->num_irqs;
318
319                 return copy_to_user((void __user *)arg, &info, minsz) ?
320                         -EFAULT : 0;
321
322         } else if (cmd == VFIO_DEVICE_GET_REGION_INFO) {
323                 struct vfio_region_info info;
324
325                 minsz = offsetofend(struct vfio_region_info, offset);
326
327                 if (copy_from_user(&info, (void __user *)arg, minsz))
328                         return -EFAULT;
329
330                 if (info.argsz < minsz)
331                         return -EINVAL;
332
333                 if (info.index >= vdev->num_regions)
334                         return -EINVAL;
335
336                 /* map offset to the physical address  */
337                 info.offset = VFIO_PLATFORM_INDEX_TO_OFFSET(info.index);
338                 info.size = vdev->regions[info.index].size;
339                 info.flags = vdev->regions[info.index].flags;
340
341                 return copy_to_user((void __user *)arg, &info, minsz) ?
342                         -EFAULT : 0;
343
344         } else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) {
345                 struct vfio_irq_info info;
346
347                 minsz = offsetofend(struct vfio_irq_info, count);
348
349                 if (copy_from_user(&info, (void __user *)arg, minsz))
350                         return -EFAULT;
351
352                 if (info.argsz < minsz)
353                         return -EINVAL;
354
355                 if (info.index >= vdev->num_irqs)
356                         return -EINVAL;
357
358                 info.flags = vdev->irqs[info.index].flags;
359                 info.count = vdev->irqs[info.index].count;
360
361                 return copy_to_user((void __user *)arg, &info, minsz) ?
362                         -EFAULT : 0;
363
364         } else if (cmd == VFIO_DEVICE_SET_IRQS) {
365                 struct vfio_irq_set hdr;
366                 u8 *data = NULL;
367                 int ret = 0;
368                 size_t data_size = 0;
369
370                 minsz = offsetofend(struct vfio_irq_set, count);
371
372                 if (copy_from_user(&hdr, (void __user *)arg, minsz))
373                         return -EFAULT;
374
375                 ret = vfio_set_irqs_validate_and_prepare(&hdr, vdev->num_irqs,
376                                                  vdev->num_irqs, &data_size);
377                 if (ret)
378                         return ret;
379
380                 if (data_size) {
381                         data = memdup_user((void __user *)(arg + minsz),
382                                             data_size);
383                         if (IS_ERR(data))
384                                 return PTR_ERR(data);
385                 }
386
387                 mutex_lock(&vdev->igate);
388
389                 ret = vfio_platform_set_irqs_ioctl(vdev, hdr.flags, hdr.index,
390                                                    hdr.start, hdr.count, data);
391                 mutex_unlock(&vdev->igate);
392                 kfree(data);
393
394                 return ret;
395
396         } else if (cmd == VFIO_DEVICE_RESET) {
397                 return vfio_platform_call_reset(vdev, NULL);
398         }
399
400         return -ENOTTY;
401 }
402
403 static ssize_t vfio_platform_read_mmio(struct vfio_platform_region *reg,
404                                        char __user *buf, size_t count,
405                                        loff_t off)
406 {
407         unsigned int done = 0;
408
409         if (!reg->ioaddr) {
410                 reg->ioaddr =
411                         ioremap(reg->addr, reg->size);
412
413                 if (!reg->ioaddr)
414                         return -ENOMEM;
415         }
416
417         while (count) {
418                 size_t filled;
419
420                 if (count >= 4 && !(off % 4)) {
421                         u32 val;
422
423                         val = ioread32(reg->ioaddr + off);
424                         if (copy_to_user(buf, &val, 4))
425                                 goto err;
426
427                         filled = 4;
428                 } else if (count >= 2 && !(off % 2)) {
429                         u16 val;
430
431                         val = ioread16(reg->ioaddr + off);
432                         if (copy_to_user(buf, &val, 2))
433                                 goto err;
434
435                         filled = 2;
436                 } else {
437                         u8 val;
438
439                         val = ioread8(reg->ioaddr + off);
440                         if (copy_to_user(buf, &val, 1))
441                                 goto err;
442
443                         filled = 1;
444                 }
445
446
447                 count -= filled;
448                 done += filled;
449                 off += filled;
450                 buf += filled;
451         }
452
453         return done;
454 err:
455         return -EFAULT;
456 }
457
458 static ssize_t vfio_platform_read(void *device_data, char __user *buf,
459                                   size_t count, loff_t *ppos)
460 {
461         struct vfio_platform_device *vdev = device_data;
462         unsigned int index = VFIO_PLATFORM_OFFSET_TO_INDEX(*ppos);
463         loff_t off = *ppos & VFIO_PLATFORM_OFFSET_MASK;
464
465         if (index >= vdev->num_regions)
466                 return -EINVAL;
467
468         if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_READ))
469                 return -EINVAL;
470
471         if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_MMIO)
472                 return vfio_platform_read_mmio(&vdev->regions[index],
473                                                         buf, count, off);
474         else if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_PIO)
475                 return -EINVAL; /* not implemented */
476
477         return -EINVAL;
478 }
479
480 static ssize_t vfio_platform_write_mmio(struct vfio_platform_region *reg,
481                                         const char __user *buf, size_t count,
482                                         loff_t off)
483 {
484         unsigned int done = 0;
485
486         if (!reg->ioaddr) {
487                 reg->ioaddr =
488                         ioremap(reg->addr, reg->size);
489
490                 if (!reg->ioaddr)
491                         return -ENOMEM;
492         }
493
494         while (count) {
495                 size_t filled;
496
497                 if (count >= 4 && !(off % 4)) {
498                         u32 val;
499
500                         if (copy_from_user(&val, buf, 4))
501                                 goto err;
502                         iowrite32(val, reg->ioaddr + off);
503
504                         filled = 4;
505                 } else if (count >= 2 && !(off % 2)) {
506                         u16 val;
507
508                         if (copy_from_user(&val, buf, 2))
509                                 goto err;
510                         iowrite16(val, reg->ioaddr + off);
511
512                         filled = 2;
513                 } else {
514                         u8 val;
515
516                         if (copy_from_user(&val, buf, 1))
517                                 goto err;
518                         iowrite8(val, reg->ioaddr + off);
519
520                         filled = 1;
521                 }
522
523                 count -= filled;
524                 done += filled;
525                 off += filled;
526                 buf += filled;
527         }
528
529         return done;
530 err:
531         return -EFAULT;
532 }
533
534 static ssize_t vfio_platform_write(void *device_data, const char __user *buf,
535                                    size_t count, loff_t *ppos)
536 {
537         struct vfio_platform_device *vdev = device_data;
538         unsigned int index = VFIO_PLATFORM_OFFSET_TO_INDEX(*ppos);
539         loff_t off = *ppos & VFIO_PLATFORM_OFFSET_MASK;
540
541         if (index >= vdev->num_regions)
542                 return -EINVAL;
543
544         if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_WRITE))
545                 return -EINVAL;
546
547         if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_MMIO)
548                 return vfio_platform_write_mmio(&vdev->regions[index],
549                                                         buf, count, off);
550         else if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_PIO)
551                 return -EINVAL; /* not implemented */
552
553         return -EINVAL;
554 }
555
556 static int vfio_platform_mmap_mmio(struct vfio_platform_region region,
557                                    struct vm_area_struct *vma)
558 {
559         u64 req_len, pgoff, req_start;
560
561         req_len = vma->vm_end - vma->vm_start;
562         pgoff = vma->vm_pgoff &
563                 ((1U << (VFIO_PLATFORM_OFFSET_SHIFT - PAGE_SHIFT)) - 1);
564         req_start = pgoff << PAGE_SHIFT;
565
566         if (region.size < PAGE_SIZE || req_start + req_len > region.size)
567                 return -EINVAL;
568
569         vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
570         vma->vm_pgoff = (region.addr >> PAGE_SHIFT) + pgoff;
571
572         return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
573                                req_len, vma->vm_page_prot);
574 }
575
576 static int vfio_platform_mmap(void *device_data, struct vm_area_struct *vma)
577 {
578         struct vfio_platform_device *vdev = device_data;
579         unsigned int index;
580
581         index = vma->vm_pgoff >> (VFIO_PLATFORM_OFFSET_SHIFT - PAGE_SHIFT);
582
583         if (vma->vm_end < vma->vm_start)
584                 return -EINVAL;
585         if (!(vma->vm_flags & VM_SHARED))
586                 return -EINVAL;
587         if (index >= vdev->num_regions)
588                 return -EINVAL;
589         if (vma->vm_start & ~PAGE_MASK)
590                 return -EINVAL;
591         if (vma->vm_end & ~PAGE_MASK)
592                 return -EINVAL;
593
594         if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_MMAP))
595                 return -EINVAL;
596
597         if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_READ)
598                         && (vma->vm_flags & VM_READ))
599                 return -EINVAL;
600
601         if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_WRITE)
602                         && (vma->vm_flags & VM_WRITE))
603                 return -EINVAL;
604
605         vma->vm_private_data = vdev;
606
607         if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_MMIO)
608                 return vfio_platform_mmap_mmio(vdev->regions[index], vma);
609
610         else if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_PIO)
611                 return -EINVAL; /* not implemented */
612
613         return -EINVAL;
614 }
615
616 static const struct vfio_device_ops vfio_platform_ops = {
617         .name           = "vfio-platform",
618         .open           = vfio_platform_open,
619         .release        = vfio_platform_release,
620         .ioctl          = vfio_platform_ioctl,
621         .read           = vfio_platform_read,
622         .write          = vfio_platform_write,
623         .mmap           = vfio_platform_mmap,
624 };
625
626 static int vfio_platform_of_probe(struct vfio_platform_device *vdev,
627                            struct device *dev)
628 {
629         int ret;
630
631         ret = device_property_read_string(dev, "compatible",
632                                           &vdev->compat);
633         if (ret)
634                 dev_err(dev, "Cannot retrieve compat for %s\n", vdev->name);
635
636         return ret;
637 }
638
639 /*
640  * There can be two kernel build combinations. One build where
641  * ACPI is not selected in Kconfig and another one with the ACPI Kconfig.
642  *
643  * In the first case, vfio_platform_acpi_probe will return since
644  * acpi_disabled is 1. DT user will not see any kind of messages from
645  * ACPI.
646  *
647  * In the second case, both DT and ACPI is compiled in but the system is
648  * booting with any of these combinations.
649  *
650  * If the firmware is DT type, then acpi_disabled is 1. The ACPI probe routine
651  * terminates immediately without any messages.
652  *
653  * If the firmware is ACPI type, then acpi_disabled is 0. All other checks are
654  * valid checks. We cannot claim that this system is DT.
655  */
656 int vfio_platform_probe_common(struct vfio_platform_device *vdev,
657                                struct device *dev)
658 {
659         struct iommu_group *group;
660         int ret;
661
662         if (!vdev)
663                 return -EINVAL;
664
665         ret = vfio_platform_acpi_probe(vdev, dev);
666         if (ret)
667                 ret = vfio_platform_of_probe(vdev, dev);
668
669         if (ret)
670                 return ret;
671
672         vdev->device = dev;
673
674         ret = vfio_platform_get_reset(vdev);
675         if (ret && vdev->reset_required) {
676                 dev_err(dev, "No reset function found for device %s\n",
677                         vdev->name);
678                 return ret;
679         }
680
681         group = vfio_iommu_group_get(dev);
682         if (!group) {
683                 dev_err(dev, "No IOMMU group for device %s\n", vdev->name);
684                 ret = -EINVAL;
685                 goto put_reset;
686         }
687
688         ret = vfio_add_group_dev(dev, &vfio_platform_ops, vdev);
689         if (ret)
690                 goto put_iommu;
691
692         mutex_init(&vdev->igate);
693
694         pm_runtime_enable(vdev->device);
695         return 0;
696
697 put_iommu:
698         vfio_iommu_group_put(group, dev);
699 put_reset:
700         vfio_platform_put_reset(vdev);
701         return ret;
702 }
703 EXPORT_SYMBOL_GPL(vfio_platform_probe_common);
704
705 struct vfio_platform_device *vfio_platform_remove_common(struct device *dev)
706 {
707         struct vfio_platform_device *vdev;
708
709         vdev = vfio_del_group_dev(dev);
710
711         if (vdev) {
712                 pm_runtime_disable(vdev->device);
713                 vfio_platform_put_reset(vdev);
714                 vfio_iommu_group_put(dev->iommu_group, dev);
715         }
716
717         return vdev;
718 }
719 EXPORT_SYMBOL_GPL(vfio_platform_remove_common);
720
721 void __vfio_platform_register_reset(struct vfio_platform_reset_node *node)
722 {
723         mutex_lock(&driver_lock);
724         list_add(&node->link, &reset_list);
725         mutex_unlock(&driver_lock);
726 }
727 EXPORT_SYMBOL_GPL(__vfio_platform_register_reset);
728
729 void vfio_platform_unregister_reset(const char *compat,
730                                     vfio_platform_reset_fn_t fn)
731 {
732         struct vfio_platform_reset_node *iter, *temp;
733
734         mutex_lock(&driver_lock);
735         list_for_each_entry_safe(iter, temp, &reset_list, link) {
736                 if (!strcmp(iter->compat, compat) && (iter->of_reset == fn)) {
737                         list_del(&iter->link);
738                         break;
739                 }
740         }
741
742         mutex_unlock(&driver_lock);
743
744 }
745 EXPORT_SYMBOL_GPL(vfio_platform_unregister_reset);
746
747 MODULE_VERSION(DRIVER_VERSION);
748 MODULE_LICENSE("GPL v2");
749 MODULE_AUTHOR(DRIVER_AUTHOR);
750 MODULE_DESCRIPTION(DRIVER_DESC);