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