11802d0beSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
236fe431fSAntonios Motakis /*
336fe431fSAntonios Motakis * Copyright (C) 2013 - Virtual Open Systems
436fe431fSAntonios Motakis * Author: Antonios Motakis <a.motakis@virtualopensystems.com>
536fe431fSAntonios Motakis */
636fe431fSAntonios Motakis
736fe431fSAntonios Motakis #include <linux/module.h>
836fe431fSAntonios Motakis #include <linux/slab.h>
936fe431fSAntonios Motakis #include <linux/vfio.h>
10ac123791SKevin Tian #include <linux/pm_runtime.h>
1136fe431fSAntonios Motakis #include <linux/amba/bus.h>
1236fe431fSAntonios Motakis
1336fe431fSAntonios Motakis #include "vfio_platform_private.h"
1436fe431fSAntonios Motakis
1536fe431fSAntonios Motakis #define DRIVER_VERSION "0.10"
1636fe431fSAntonios Motakis #define DRIVER_AUTHOR "Antonios Motakis <a.motakis@virtualopensystems.com>"
1736fe431fSAntonios Motakis #define DRIVER_DESC "VFIO for AMBA devices - User Level meta-driver"
1836fe431fSAntonios Motakis
1936fe431fSAntonios Motakis /* probing devices from the AMBA bus */
2036fe431fSAntonios Motakis
get_amba_resource(struct vfio_platform_device * vdev,int i)2136fe431fSAntonios Motakis static struct resource *get_amba_resource(struct vfio_platform_device *vdev,
2236fe431fSAntonios Motakis int i)
2336fe431fSAntonios Motakis {
2436fe431fSAntonios Motakis struct amba_device *adev = (struct amba_device *) vdev->opaque;
2536fe431fSAntonios Motakis
2636fe431fSAntonios Motakis if (i == 0)
2736fe431fSAntonios Motakis return &adev->res;
2836fe431fSAntonios Motakis
2936fe431fSAntonios Motakis return NULL;
3036fe431fSAntonios Motakis }
3136fe431fSAntonios Motakis
get_amba_irq(struct vfio_platform_device * vdev,int i)3236fe431fSAntonios Motakis static int get_amba_irq(struct vfio_platform_device *vdev, int i)
3336fe431fSAntonios Motakis {
3436fe431fSAntonios Motakis struct amba_device *adev = (struct amba_device *) vdev->opaque;
3536fe431fSAntonios Motakis int ret = 0;
3636fe431fSAntonios Motakis
3736fe431fSAntonios Motakis if (i < AMBA_NR_IRQS)
3836fe431fSAntonios Motakis ret = adev->irq[i];
3936fe431fSAntonios Motakis
4036fe431fSAntonios Motakis /* zero is an unset IRQ for AMBA devices */
4136fe431fSAntonios Motakis return ret ? ret : -ENXIO;
4236fe431fSAntonios Motakis }
4336fe431fSAntonios Motakis
vfio_amba_init_dev(struct vfio_device * core_vdev)44ac123791SKevin Tian static int vfio_amba_init_dev(struct vfio_device *core_vdev)
4536fe431fSAntonios Motakis {
46ac123791SKevin Tian struct vfio_platform_device *vdev =
47ac123791SKevin Tian container_of(core_vdev, struct vfio_platform_device, vdev);
48ac123791SKevin Tian struct amba_device *adev = to_amba_device(core_vdev->dev);
4936fe431fSAntonios Motakis int ret;
5036fe431fSAntonios Motakis
5136fe431fSAntonios Motakis vdev->name = kasprintf(GFP_KERNEL, "vfio-amba-%08x", adev->periphid);
52ac123791SKevin Tian if (!vdev->name)
5336fe431fSAntonios Motakis return -ENOMEM;
5436fe431fSAntonios Motakis
5536fe431fSAntonios Motakis vdev->opaque = (void *) adev;
5636fe431fSAntonios Motakis vdev->flags = VFIO_DEVICE_FLAGS_AMBA;
5736fe431fSAntonios Motakis vdev->get_resource = get_amba_resource;
5836fe431fSAntonios Motakis vdev->get_irq = get_amba_irq;
59b5add544SSinan Kaya vdev->reset_required = false;
6036fe431fSAntonios Motakis
61ac123791SKevin Tian ret = vfio_platform_init_common(vdev);
62ac123791SKevin Tian if (ret)
6336fe431fSAntonios Motakis kfree(vdev->name);
64cb616458SJason Gunthorpe return ret;
6536fe431fSAntonios Motakis }
6636fe431fSAntonios Motakis
67ac123791SKevin Tian static const struct vfio_device_ops vfio_amba_ops;
vfio_amba_probe(struct amba_device * adev,const struct amba_id * id)68ac123791SKevin Tian static int vfio_amba_probe(struct amba_device *adev, const struct amba_id *id)
69ac123791SKevin Tian {
70ac123791SKevin Tian struct vfio_platform_device *vdev;
71ac123791SKevin Tian int ret;
72ac123791SKevin Tian
73ac123791SKevin Tian vdev = vfio_alloc_device(vfio_platform_device, vdev, &adev->dev,
74ac123791SKevin Tian &vfio_amba_ops);
75ac123791SKevin Tian if (IS_ERR(vdev))
76ac123791SKevin Tian return PTR_ERR(vdev);
77ac123791SKevin Tian
78ac123791SKevin Tian ret = vfio_register_group_dev(&vdev->vdev);
79ac123791SKevin Tian if (ret)
80ac123791SKevin Tian goto out_put_vdev;
81ac123791SKevin Tian
82ac123791SKevin Tian pm_runtime_enable(&adev->dev);
83cb616458SJason Gunthorpe dev_set_drvdata(&adev->dev, vdev);
84cb616458SJason Gunthorpe return 0;
85ac123791SKevin Tian
86ac123791SKevin Tian out_put_vdev:
87ac123791SKevin Tian vfio_put_device(&vdev->vdev);
88ac123791SKevin Tian return ret;
89ac123791SKevin Tian }
90ac123791SKevin Tian
vfio_amba_release_dev(struct vfio_device * core_vdev)91ac123791SKevin Tian static void vfio_amba_release_dev(struct vfio_device *core_vdev)
92ac123791SKevin Tian {
93ac123791SKevin Tian struct vfio_platform_device *vdev =
94ac123791SKevin Tian container_of(core_vdev, struct vfio_platform_device, vdev);
95ac123791SKevin Tian
96ac123791SKevin Tian vfio_platform_release_common(vdev);
97ac123791SKevin Tian kfree(vdev->name);
9836fe431fSAntonios Motakis }
9936fe431fSAntonios Motakis
vfio_amba_remove(struct amba_device * adev)1003fd269e7SUwe Kleine-König static void vfio_amba_remove(struct amba_device *adev)
10136fe431fSAntonios Motakis {
102cb616458SJason Gunthorpe struct vfio_platform_device *vdev = dev_get_drvdata(&adev->dev);
10336fe431fSAntonios Motakis
104ac123791SKevin Tian vfio_unregister_group_dev(&vdev->vdev);
105ac123791SKevin Tian pm_runtime_disable(vdev->device);
106ac123791SKevin Tian vfio_put_device(&vdev->vdev);
10736fe431fSAntonios Motakis }
10836fe431fSAntonios Motakis
109ac123791SKevin Tian static const struct vfio_device_ops vfio_amba_ops = {
110ac123791SKevin Tian .name = "vfio-amba",
111ac123791SKevin Tian .init = vfio_amba_init_dev,
112ac123791SKevin Tian .release = vfio_amba_release_dev,
113ac123791SKevin Tian .open_device = vfio_platform_open_device,
114ac123791SKevin Tian .close_device = vfio_platform_close_device,
115ac123791SKevin Tian .ioctl = vfio_platform_ioctl,
116ac123791SKevin Tian .read = vfio_platform_read,
117ac123791SKevin Tian .write = vfio_platform_write,
118ac123791SKevin Tian .mmap = vfio_platform_mmap,
119a4d1f91dSJason Gunthorpe .bind_iommufd = vfio_iommufd_physical_bind,
120a4d1f91dSJason Gunthorpe .unbind_iommufd = vfio_iommufd_physical_unbind,
121a4d1f91dSJason Gunthorpe .attach_ioas = vfio_iommufd_physical_attach_ioas,
1229048c734SYi Liu .detach_ioas = vfio_iommufd_physical_detach_ioas,
123ac123791SKevin Tian };
124ac123791SKevin Tian
125*ec29d22cSGeert Uytterhoeven static const struct amba_id vfio_amba_ids[] = {
12636fe431fSAntonios Motakis { 0, 0 },
12736fe431fSAntonios Motakis };
12836fe431fSAntonios Motakis
129*ec29d22cSGeert Uytterhoeven MODULE_DEVICE_TABLE(amba, vfio_amba_ids);
13036fe431fSAntonios Motakis
13136fe431fSAntonios Motakis static struct amba_driver vfio_amba_driver = {
13236fe431fSAntonios Motakis .probe = vfio_amba_probe,
13336fe431fSAntonios Motakis .remove = vfio_amba_remove,
134*ec29d22cSGeert Uytterhoeven .id_table = vfio_amba_ids,
13536fe431fSAntonios Motakis .drv = {
13636fe431fSAntonios Motakis .name = "vfio-amba",
13736fe431fSAntonios Motakis },
13870693f47SLu Baolu .driver_managed_dma = true,
13936fe431fSAntonios Motakis };
14036fe431fSAntonios Motakis
14136fe431fSAntonios Motakis module_amba_driver(vfio_amba_driver);
14236fe431fSAntonios Motakis
14336fe431fSAntonios Motakis MODULE_VERSION(DRIVER_VERSION);
14436fe431fSAntonios Motakis MODULE_LICENSE("GPL v2");
14536fe431fSAntonios Motakis MODULE_AUTHOR(DRIVER_AUTHOR);
14636fe431fSAntonios Motakis MODULE_DESCRIPTION(DRIVER_DESC);
147