696 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2013 - Virtual Open Systems4 * Author: Antonios Motakis <a.motakis@virtualopensystems.com>5 */6 7#define dev_fmt(fmt) "VFIO: " fmt8 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_ACPI66 vdev->acpihid = acpi_device_hid(adev);67#endif68 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_ACPI75 struct device *dev = vdev->device;76 acpi_handle handle = ACPI_HANDLE(dev);77 acpi_status acpi_ret;78 79 acpi_ret = acpi_evaluate_object(handle, "_RST", NULL, NULL);80 if (ACPI_FAILURE(acpi_ret)) {81 if (extra_dbg)82 *extra_dbg = acpi_format_exception(acpi_ret);83 return -EINVAL;84 }85 86 return 0;87#else88 return -ENOENT;89#endif90}91 92static bool vfio_platform_acpi_has_reset(struct vfio_platform_device *vdev)93{94#ifdef CONFIG_ACPI95 struct device *dev = vdev->device;96 acpi_handle handle = ACPI_HANDLE(dev);97 98 return acpi_has_method(handle, "_RST");99#else100 return false;101#endif102}103 104static bool vfio_platform_has_reset(struct vfio_platform_device *vdev)105{106 if (VFIO_PLATFORM_IS_ACPI(vdev))107 return vfio_platform_acpi_has_reset(vdev);108 109 return vdev->of_reset ? true : false;110}111 112static int vfio_platform_get_reset(struct vfio_platform_device *vdev)113{114 if (VFIO_PLATFORM_IS_ACPI(vdev))115 return vfio_platform_acpi_has_reset(vdev) ? 0 : -ENOENT;116 117 vdev->of_reset = vfio_platform_lookup_reset(vdev->compat,118 &vdev->reset_module);119 if (!vdev->of_reset) {120 request_module("vfio-reset:%s", vdev->compat);121 vdev->of_reset = vfio_platform_lookup_reset(vdev->compat,122 &vdev->reset_module);123 }124 125 return vdev->of_reset ? 0 : -ENOENT;126}127 128static void vfio_platform_put_reset(struct vfio_platform_device *vdev)129{130 if (VFIO_PLATFORM_IS_ACPI(vdev))131 return;132 133 if (vdev->of_reset)134 module_put(vdev->reset_module);135}136 137static int vfio_platform_regions_init(struct vfio_platform_device *vdev)138{139 int cnt = 0, i;140 141 while (vdev->get_resource(vdev, cnt))142 cnt++;143 144 vdev->regions = kcalloc(cnt, sizeof(struct vfio_platform_region),145 GFP_KERNEL_ACCOUNT);146 if (!vdev->regions)147 return -ENOMEM;148 149 for (i = 0; i < cnt; i++) {150 struct resource *res =151 vdev->get_resource(vdev, i);152 153 vdev->regions[i].addr = res->start;154 vdev->regions[i].size = resource_size(res);155 vdev->regions[i].flags = 0;156 157 switch (resource_type(res)) {158 case IORESOURCE_MEM:159 vdev->regions[i].type = VFIO_PLATFORM_REGION_TYPE_MMIO;160 vdev->regions[i].flags |= VFIO_REGION_INFO_FLAG_READ;161 if (!(res->flags & IORESOURCE_READONLY))162 vdev->regions[i].flags |=163 VFIO_REGION_INFO_FLAG_WRITE;164 165 /*166 * Only regions addressed with PAGE granularity may be167 * MMAPed securely.168 */169 if (!(vdev->regions[i].addr & ~PAGE_MASK) &&170 !(vdev->regions[i].size & ~PAGE_MASK))171 vdev->regions[i].flags |=172 VFIO_REGION_INFO_FLAG_MMAP;173 174 break;175 case IORESOURCE_IO:176 vdev->regions[i].type = VFIO_PLATFORM_REGION_TYPE_PIO;177 break;178 default:179 goto err;180 }181 }182 183 vdev->num_regions = cnt;184 185 return 0;186err:187 kfree(vdev->regions);188 return -EINVAL;189}190 191static void vfio_platform_regions_cleanup(struct vfio_platform_device *vdev)192{193 int i;194 195 for (i = 0; i < vdev->num_regions; i++)196 iounmap(vdev->regions[i].ioaddr);197 198 vdev->num_regions = 0;199 kfree(vdev->regions);200}201 202static int vfio_platform_call_reset(struct vfio_platform_device *vdev,203 const char **extra_dbg)204{205 if (VFIO_PLATFORM_IS_ACPI(vdev)) {206 dev_info(vdev->device, "reset\n");207 return vfio_platform_acpi_call_reset(vdev, extra_dbg);208 } else if (vdev->of_reset) {209 dev_info(vdev->device, "reset\n");210 return vdev->of_reset(vdev);211 }212 213 dev_warn(vdev->device, "no reset function found!\n");214 return -EINVAL;215}216 217void vfio_platform_close_device(struct vfio_device *core_vdev)218{219 struct vfio_platform_device *vdev =220 container_of(core_vdev, struct vfio_platform_device, vdev);221 const char *extra_dbg = NULL;222 int ret;223 224 ret = vfio_platform_call_reset(vdev, &extra_dbg);225 if (WARN_ON(ret && vdev->reset_required)) {226 dev_warn(227 vdev->device,228 "reset driver is required and reset call failed in release (%d) %s\n",229 ret, extra_dbg ? extra_dbg : "");230 }231 pm_runtime_put(vdev->device);232 vfio_platform_regions_cleanup(vdev);233 vfio_platform_irq_cleanup(vdev);234}235EXPORT_SYMBOL_GPL(vfio_platform_close_device);236 237int vfio_platform_open_device(struct vfio_device *core_vdev)238{239 struct vfio_platform_device *vdev =240 container_of(core_vdev, struct vfio_platform_device, vdev);241 const char *extra_dbg = NULL;242 int ret;243 244 ret = vfio_platform_regions_init(vdev);245 if (ret)246 return ret;247 248 ret = vfio_platform_irq_init(vdev);249 if (ret)250 goto err_irq;251 252 ret = pm_runtime_get_sync(vdev->device);253 if (ret < 0)254 goto err_rst;255 256 ret = vfio_platform_call_reset(vdev, &extra_dbg);257 if (ret && vdev->reset_required) {258 dev_warn(259 vdev->device,260 "reset driver is required and reset call failed in open (%d) %s\n",261 ret, extra_dbg ? extra_dbg : "");262 goto err_rst;263 }264 return 0;265 266err_rst:267 pm_runtime_put(vdev->device);268 vfio_platform_irq_cleanup(vdev);269err_irq:270 vfio_platform_regions_cleanup(vdev);271 return ret;272}273EXPORT_SYMBOL_GPL(vfio_platform_open_device);274 275long vfio_platform_ioctl(struct vfio_device *core_vdev,276 unsigned int cmd, unsigned long arg)277{278 struct vfio_platform_device *vdev =279 container_of(core_vdev, struct vfio_platform_device, vdev);280 281 unsigned long minsz;282 283 if (cmd == VFIO_DEVICE_GET_INFO) {284 struct vfio_device_info info;285 286 minsz = offsetofend(struct vfio_device_info, num_irqs);287 288 if (copy_from_user(&info, (void __user *)arg, minsz))289 return -EFAULT;290 291 if (info.argsz < minsz)292 return -EINVAL;293 294 if (vfio_platform_has_reset(vdev))295 vdev->flags |= VFIO_DEVICE_FLAGS_RESET;296 info.flags = vdev->flags;297 info.num_regions = vdev->num_regions;298 info.num_irqs = vdev->num_irqs;299 300 return copy_to_user((void __user *)arg, &info, minsz) ?301 -EFAULT : 0;302 303 } else if (cmd == VFIO_DEVICE_GET_REGION_INFO) {304 struct vfio_region_info info;305 306 minsz = offsetofend(struct vfio_region_info, offset);307 308 if (copy_from_user(&info, (void __user *)arg, minsz))309 return -EFAULT;310 311 if (info.argsz < minsz)312 return -EINVAL;313 314 if (info.index >= vdev->num_regions)315 return -EINVAL;316 317 /* map offset to the physical address */318 info.offset = VFIO_PLATFORM_INDEX_TO_OFFSET(info.index);319 info.size = vdev->regions[info.index].size;320 info.flags = vdev->regions[info.index].flags;321 322 return copy_to_user((void __user *)arg, &info, minsz) ?323 -EFAULT : 0;324 325 } else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) {326 struct vfio_irq_info info;327 328 minsz = offsetofend(struct vfio_irq_info, count);329 330 if (copy_from_user(&info, (void __user *)arg, minsz))331 return -EFAULT;332 333 if (info.argsz < minsz)334 return -EINVAL;335 336 if (info.index >= vdev->num_irqs)337 return -EINVAL;338 339 info.flags = vdev->irqs[info.index].flags;340 info.count = vdev->irqs[info.index].count;341 342 return copy_to_user((void __user *)arg, &info, minsz) ?343 -EFAULT : 0;344 345 } else if (cmd == VFIO_DEVICE_SET_IRQS) {346 struct vfio_irq_set hdr;347 u8 *data = NULL;348 int ret = 0;349 size_t data_size = 0;350 351 minsz = offsetofend(struct vfio_irq_set, count);352 353 if (copy_from_user(&hdr, (void __user *)arg, minsz))354 return -EFAULT;355 356 ret = vfio_set_irqs_validate_and_prepare(&hdr, vdev->num_irqs,357 vdev->num_irqs, &data_size);358 if (ret)359 return ret;360 361 if (data_size) {362 data = memdup_user((void __user *)(arg + minsz),363 data_size);364 if (IS_ERR(data))365 return PTR_ERR(data);366 }367 368 mutex_lock(&vdev->igate);369 370 ret = vfio_platform_set_irqs_ioctl(vdev, hdr.flags, hdr.index,371 hdr.start, hdr.count, data);372 mutex_unlock(&vdev->igate);373 kfree(data);374 375 return ret;376 377 } else if (cmd == VFIO_DEVICE_RESET) {378 return vfio_platform_call_reset(vdev, NULL);379 }380 381 return -ENOTTY;382}383EXPORT_SYMBOL_GPL(vfio_platform_ioctl);384 385static ssize_t vfio_platform_read_mmio(struct vfio_platform_region *reg,386 char __user *buf, size_t count,387 loff_t off)388{389 unsigned int done = 0;390 391 if (!reg->ioaddr) {392 reg->ioaddr =393 ioremap(reg->addr, reg->size);394 395 if (!reg->ioaddr)396 return -ENOMEM;397 }398 399 while (count) {400 size_t filled;401 402 if (count >= 4 && !(off % 4)) {403 u32 val;404 405 val = ioread32(reg->ioaddr + off);406 if (copy_to_user(buf, &val, 4))407 goto err;408 409 filled = 4;410 } else if (count >= 2 && !(off % 2)) {411 u16 val;412 413 val = ioread16(reg->ioaddr + off);414 if (copy_to_user(buf, &val, 2))415 goto err;416 417 filled = 2;418 } else {419 u8 val;420 421 val = ioread8(reg->ioaddr + off);422 if (copy_to_user(buf, &val, 1))423 goto err;424 425 filled = 1;426 }427 428 429 count -= filled;430 done += filled;431 off += filled;432 buf += filled;433 }434 435 return done;436err:437 return -EFAULT;438}439 440ssize_t vfio_platform_read(struct vfio_device *core_vdev,441 char __user *buf, size_t count, loff_t *ppos)442{443 struct vfio_platform_device *vdev =444 container_of(core_vdev, struct vfio_platform_device, vdev);445 unsigned int index = VFIO_PLATFORM_OFFSET_TO_INDEX(*ppos);446 loff_t off = *ppos & VFIO_PLATFORM_OFFSET_MASK;447 448 if (index >= vdev->num_regions)449 return -EINVAL;450 451 if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_READ))452 return -EINVAL;453 454 if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_MMIO)455 return vfio_platform_read_mmio(&vdev->regions[index],456 buf, count, off);457 else if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_PIO)458 return -EINVAL; /* not implemented */459 460 return -EINVAL;461}462EXPORT_SYMBOL_GPL(vfio_platform_read);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 518ssize_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}540EXPORT_SYMBOL_GPL(vfio_platform_write);541 542static int vfio_platform_mmap_mmio(struct vfio_platform_region region,543 struct vm_area_struct *vma)544{545 u64 req_len, pgoff, req_start;546 547 req_len = vma->vm_end - vma->vm_start;548 pgoff = vma->vm_pgoff &549 ((1U << (VFIO_PLATFORM_OFFSET_SHIFT - PAGE_SHIFT)) - 1);550 req_start = pgoff << PAGE_SHIFT;551 552 if (region.size < PAGE_SIZE || req_start + req_len > region.size)553 return -EINVAL;554 555 vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);556 vma->vm_pgoff = (region.addr >> PAGE_SHIFT) + pgoff;557 558 return remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,559 req_len, vma->vm_page_prot);560}561 562int vfio_platform_mmap(struct vfio_device *core_vdev, struct vm_area_struct *vma)563{564 struct vfio_platform_device *vdev =565 container_of(core_vdev, struct vfio_platform_device, vdev);566 unsigned int index;567 568 index = vma->vm_pgoff >> (VFIO_PLATFORM_OFFSET_SHIFT - PAGE_SHIFT);569 570 if (vma->vm_end < vma->vm_start)571 return -EINVAL;572 if (!(vma->vm_flags & VM_SHARED))573 return -EINVAL;574 if (index >= vdev->num_regions)575 return -EINVAL;576 if (vma->vm_start & ~PAGE_MASK)577 return -EINVAL;578 if (vma->vm_end & ~PAGE_MASK)579 return -EINVAL;580 581 if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_MMAP))582 return -EINVAL;583 584 if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_READ)585 && (vma->vm_flags & VM_READ))586 return -EINVAL;587 588 if (!(vdev->regions[index].flags & VFIO_REGION_INFO_FLAG_WRITE)589 && (vma->vm_flags & VM_WRITE))590 return -EINVAL;591 592 vma->vm_private_data = vdev;593 594 if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_MMIO)595 return vfio_platform_mmap_mmio(vdev->regions[index], vma);596 597 else if (vdev->regions[index].type & VFIO_PLATFORM_REGION_TYPE_PIO)598 return -EINVAL; /* not implemented */599 600 return -EINVAL;601}602EXPORT_SYMBOL_GPL(vfio_platform_mmap);603 604static int vfio_platform_of_probe(struct vfio_platform_device *vdev,605 struct device *dev)606{607 int ret;608 609 ret = device_property_read_string(dev, "compatible",610 &vdev->compat);611 if (ret)612 dev_err(dev, "Cannot retrieve compat for %s\n", vdev->name);613 614 return ret;615}616 617/*618 * There can be two kernel build combinations. One build where619 * ACPI is not selected in Kconfig and another one with the ACPI Kconfig.620 *621 * In the first case, vfio_platform_acpi_probe will return since622 * acpi_disabled is 1. DT user will not see any kind of messages from623 * ACPI.624 *625 * In the second case, both DT and ACPI is compiled in but the system is626 * booting with any of these combinations.627 *628 * If the firmware is DT type, then acpi_disabled is 1. The ACPI probe routine629 * terminates immediately without any messages.630 *631 * If the firmware is ACPI type, then acpi_disabled is 0. All other checks are632 * valid checks. We cannot claim that this system is DT.633 */634int vfio_platform_init_common(struct vfio_platform_device *vdev)635{636 int ret;637 struct device *dev = vdev->vdev.dev;638 639 ret = vfio_platform_acpi_probe(vdev, dev);640 if (ret)641 ret = vfio_platform_of_probe(vdev, dev);642 643 if (ret)644 return ret;645 646 vdev->device = dev;647 mutex_init(&vdev->igate);648 649 ret = vfio_platform_get_reset(vdev);650 if (ret && vdev->reset_required) {651 dev_err(dev, "No reset function found for device %s\n",652 vdev->name);653 return ret;654 }655 656 return 0;657}658EXPORT_SYMBOL_GPL(vfio_platform_init_common);659 660void vfio_platform_release_common(struct vfio_platform_device *vdev)661{662 vfio_platform_put_reset(vdev);663}664EXPORT_SYMBOL_GPL(vfio_platform_release_common);665 666void __vfio_platform_register_reset(struct vfio_platform_reset_node *node)667{668 mutex_lock(&driver_lock);669 list_add(&node->link, &reset_list);670 mutex_unlock(&driver_lock);671}672EXPORT_SYMBOL_GPL(__vfio_platform_register_reset);673 674void vfio_platform_unregister_reset(const char *compat,675 vfio_platform_reset_fn_t fn)676{677 struct vfio_platform_reset_node *iter, *temp;678 679 mutex_lock(&driver_lock);680 list_for_each_entry_safe(iter, temp, &reset_list, link) {681 if (!strcmp(iter->compat, compat) && (iter->of_reset == fn)) {682 list_del(&iter->link);683 break;684 }685 }686 687 mutex_unlock(&driver_lock);688 689}690EXPORT_SYMBOL_GPL(vfio_platform_unregister_reset);691 692MODULE_VERSION(DRIVER_VERSION);693MODULE_LICENSE("GPL v2");694MODULE_AUTHOR(DRIVER_AUTHOR);695MODULE_DESCRIPTION(DRIVER_DESC);696