summaryrefslogtreecommitdiff
path: root/drivers/vfio/fsl-mc/vfio_fsl_mc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/vfio/fsl-mc/vfio_fsl_mc.c')
-rw-r--r--drivers/vfio/fsl-mc/vfio_fsl_mc.c83
1 files changed, 79 insertions, 4 deletions
diff --git a/drivers/vfio/fsl-mc/vfio_fsl_mc.c b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
index 29312b9..91decea 100644
--- a/drivers/vfio/fsl-mc/vfio_fsl_mc.c
+++ b/drivers/vfio/fsl-mc/vfio_fsl_mc.c
@@ -87,12 +87,18 @@ static int vfio_fsl_mc_open(void *device_data)
ret = vfio_fsl_mc_regions_init(vdev);
if (ret)
goto error_region_init;
+
+ ret = vfio_fsl_mc_irqs_init(vdev);
+ if (ret)
+ goto error_irq_init;
}
vdev->refcnt++;
mutex_unlock(&driver_lock);
return 0;
+error_irq_init:
+ vfio_fsl_mc_regions_cleanup(vdev);
error_region_init:
mutex_unlock(&driver_lock);
if (ret)
@@ -107,8 +113,10 @@ static void vfio_fsl_mc_release(void *device_data)
mutex_lock(&driver_lock);
- if (!(--vdev->refcnt))
+ if (!(--vdev->refcnt)) {
vfio_fsl_mc_regions_cleanup(vdev);
+ vfio_fsl_mc_irqs_cleanup(vdev);
+ }
mutex_unlock(&driver_lock);
@@ -168,7 +176,31 @@ static long vfio_fsl_mc_ioctl(void *device_data, unsigned int cmd,
}
case VFIO_DEVICE_GET_IRQ_INFO:
{
- return -EINVAL;
+ struct vfio_irq_info info;
+
+ minsz = offsetofend(struct vfio_irq_info, count);
+ if (copy_from_user(&info, (void __user *)arg, minsz))
+ return -EFAULT;
+
+ if (info.argsz < minsz)
+ return -EINVAL;
+
+ if (info.index >= mc_dev->obj_desc.irq_count)
+ return -EINVAL;
+
+ if (vdev->mc_irqs != NULL) {
+ info.flags = vdev->mc_irqs[info.index].flags;
+ info.count = vdev->mc_irqs[info.index].count;
+ } else {
+ /*
+ * If IRQs are not initialized then these can not
+ * be configuted and used by user-space/
+ */
+ info.flags = 0;
+ info.count = 0;
+ }
+
+ return copy_to_user((void __user *)arg, &info, minsz);
}
case VFIO_DEVICE_SET_IRQS:
{
@@ -282,6 +314,7 @@ static int vfio_fsl_mc_initialize_dprc(struct vfio_fsl_mc_device *vdev)
struct fsl_mc_device *mc_dev = vdev->mc_dev;
struct device *dev = &mc_dev->dev;
struct fsl_mc_bus *mc_bus;
+ struct irq_domain *mc_msi_domain;
unsigned int irq_count;
int ret;
@@ -301,7 +334,7 @@ static int vfio_fsl_mc_initialize_dprc(struct vfio_fsl_mc_device *vdev)
FSL_MC_IO_ATOMIC_CONTEXT_PORTAL,
&mc_dev->mc_io);
if (ret < 0)
- return ret;
+ goto clean_msi_domain;
/* Reset MCP before move on */
ret = fsl_mc_portal_reset(mc_dev->mc_io);
@@ -310,6 +343,13 @@ static int vfio_fsl_mc_initialize_dprc(struct vfio_fsl_mc_device *vdev)
goto free_mc_portal;
}
+ /* MSI domain set up */
+ ret = fsl_mc_find_msi_domain(root_dprc_dev->parent, &mc_msi_domain);
+ if (ret < 0)
+ goto free_mc_portal;
+
+ dev_set_msi_domain(&mc_dev->dev, mc_msi_domain);
+
ret = dprc_open(mc_dev->mc_io, 0, mc_dev->obj_desc.id,
&mc_dev->mc_handle);
if (ret) {
@@ -322,6 +362,15 @@ static int vfio_fsl_mc_initialize_dprc(struct vfio_fsl_mc_device *vdev)
mc_bus = to_fsl_mc_bus(mc_dev);
+ if (!mc_bus->irq_resources) {
+ irq_count = FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS;
+ ret = fsl_mc_populate_irq_pool(mc_bus, irq_count);
+ if (ret < 0) {
+ dev_err(dev, "%s: Failed to init irq-pool\n", __func__);
+ goto clean_resource_pool;
+ }
+ }
+
mutex_init(&mc_bus->scan_mutex);
mutex_lock(&mc_bus->scan_mutex);
@@ -330,17 +379,30 @@ static int vfio_fsl_mc_initialize_dprc(struct vfio_fsl_mc_device *vdev)
mutex_unlock(&mc_bus->scan_mutex);
if (ret) {
dev_err(dev, "dprc_scan_objects() fails (%d)\n", ret);
- goto clean_resource_pool;
+ goto clean_irq_pool;
+ }
+
+ if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) {
+ dev_warn(&mc_dev->dev,
+ "IRQs needed (%u) exceed IRQs preallocated (%u)\n",
+ irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS);
}
return 0;
+clean_irq_pool:
+ fsl_mc_cleanup_irq_pool(mc_bus);
+
clean_resource_pool:
fsl_mc_cleanup_all_resource_pools(mc_dev);
dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
free_mc_portal:
fsl_mc_portal_free(mc_dev->mc_io);
+
+clean_msi_domain:
+ dev_set_msi_domain(&mc_dev->dev, NULL);
+
return ret;
}
@@ -361,6 +423,7 @@ static int vfio_fsl_mc_device_remove(struct device *dev, void *data)
static void vfio_fsl_mc_cleanup_dprc(struct vfio_fsl_mc_device *vdev)
{
struct fsl_mc_device *mc_dev = vdev->mc_dev;
+ struct fsl_mc_bus *mc_bus;
/* device must be DPRC */
if (strcmp(mc_dev->obj_desc.type, "dprc"))
@@ -368,6 +431,12 @@ static void vfio_fsl_mc_cleanup_dprc(struct vfio_fsl_mc_device *vdev)
device_for_each_child(&mc_dev->dev, NULL, vfio_fsl_mc_device_remove);
+ mc_bus = to_fsl_mc_bus(mc_dev);
+ if (dev_get_msi_domain(&mc_dev->dev))
+ fsl_mc_cleanup_irq_pool(mc_bus);
+
+ dev_set_msi_domain(&mc_dev->dev, NULL);
+
fsl_mc_cleanup_all_resource_pools(mc_dev);
dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle);
fsl_mc_portal_free(mc_dev->mc_io);
@@ -418,6 +487,10 @@ static int vfio_fsl_mc_probe(struct fsl_mc_device *mc_dev)
}
mc_dev->mc_io = mc_bus_dev->mc_io;
+
+ /* Inherit parent MSI domain */
+ dev_set_msi_domain(&mc_dev->dev,
+ dev_get_msi_domain(mc_dev->dev.parent));
}
return 0;
@@ -438,6 +511,8 @@ static int vfio_fsl_mc_remove(struct fsl_mc_device *mc_dev)
if (strcmp(mc_dev->obj_desc.type, "dprc") == 0)
vfio_fsl_mc_cleanup_dprc(vdev);
+ else
+ dev_set_msi_domain(&mc_dev->dev, NULL);
mc_dev->mc_io = NULL;