xref: /linux/drivers/vfio/platform/vfio_amba.c (revision 4853f1f6ace32c68a04287353e428c4cfc3fa8ed)
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