summaryrefslogtreecommitdiff
path: root/kernel/irq/msi.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/irq/msi.c')
-rw-r--r--kernel/irq/msi.c48
1 files changed, 48 insertions, 0 deletions
diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
index 6ffe75eeba59..b511dc1a0219 100644
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -119,6 +119,32 @@ fail:
return -ENOMEM;
}
+/**
+ * msi_free_msi_descs_range - Free MSI descriptors of a device
+ * @dev: Device to free the descriptors
+ * @filter: Descriptor state filter
+ * @first_index: Index to start freeing from
+ * @last_index: Last index to be freed
+ */
+void msi_free_msi_descs_range(struct device *dev, enum msi_desc_filter filter,
+ unsigned int first_index, unsigned int last_index)
+{
+ struct msi_desc *desc;
+
+ lockdep_assert_held(&dev->msi.data->mutex);
+
+ msi_for_each_desc(desc, dev, filter) {
+ /*
+ * Stupid for now to handle MSI device domain until the
+ * storage is switched over to an xarray.
+ */
+ if (desc->msi_index < first_index || desc->msi_index > last_index)
+ continue;
+ list_del(&desc->list);
+ free_msi_entry(desc);
+ }
+}
+
void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
{
*msg = entry->msg;
@@ -879,6 +905,16 @@ skip_activate:
return 0;
}
+static int msi_domain_add_simple_msi_descs(struct msi_domain_info *info,
+ struct device *dev,
+ unsigned int num_descs)
+{
+ if (!(info->flags & MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS))
+ return 0;
+
+ return msi_add_simple_msi_descs(dev, 0, num_descs);
+}
+
/**
* msi_domain_alloc_irqs_descs_locked - Allocate interrupts from a MSI interrupt domain
* @domain: The domain to allocate from
@@ -901,6 +937,10 @@ int msi_domain_alloc_irqs_descs_locked(struct irq_domain *domain, struct device
lockdep_assert_held(&dev->msi.data->mutex);
+ ret = msi_domain_add_simple_msi_descs(info, dev, nvec);
+ if (ret)
+ return ret;
+
ret = ops->domain_alloc_irqs(domain, dev, nvec);
if (ret)
goto cleanup;
@@ -962,6 +1002,13 @@ void __msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)
}
}
+static void msi_domain_free_msi_descs(struct msi_domain_info *info,
+ struct device *dev)
+{
+ if (info->flags & MSI_FLAG_FREE_MSI_DESCS)
+ msi_free_msi_descs(dev);
+}
+
/**
* msi_domain_free_irqs_descs_locked - Free interrupts from a MSI interrupt @domain associated to @dev
* @domain: The domain to managing the interrupts
@@ -982,6 +1029,7 @@ void msi_domain_free_irqs_descs_locked(struct irq_domain *domain, struct device
if (info->flags & MSI_FLAG_DEV_SYSFS)
msi_device_destroy_sysfs(dev);
ops->domain_free_irqs(domain, dev);
+ msi_domain_free_msi_descs(info, dev);
}
/**