Provide domain info flags which tell the core to allocate simple
descriptors or to free descriptors when the interrupts are freed and
implement the required functionality.

Signed-off-by: Thomas Gleixner <t...@linutronix.de>
---
 include/linux/msi.h |   17 +++++++++++++++++
 kernel/irq/msi.c    |   48 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 65 insertions(+)

--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -106,6 +106,8 @@ struct pci_msi_desc {
        };
 };
 
+#define MSI_MAX_INDEX          ((unsigned int)USHRT_MAX)
+
 /**
  * struct msi_desc - Descriptor structure for MSI based interrupts
  * @list:      List head for management
@@ -264,6 +266,17 @@ static inline void pci_write_msi_msg(uns
 #endif /* CONFIG_PCI_MSI */
 
 int msi_add_msi_desc(struct device *dev, struct msi_desc *init_desc);
+void msi_free_msi_descs_range(struct device *dev, enum msi_desc_filter filter,
+                             unsigned int first_index, unsigned int 
last_index);
+
+/**
+ * msi_free_msi_descs - Free MSI descriptors of a device
+ * @dev:       Device to free the descriptors
+ */
+static inline void msi_free_msi_descs(struct device *dev)
+{
+       msi_free_msi_descs_range(dev, MSI_DESC_ALL, 0, MSI_MAX_INDEX);
+}
 
 struct msi_desc *alloc_msi_entry(struct device *dev, int nvec,
                                 const struct irq_affinity_desc *affinity);
@@ -424,6 +437,10 @@ enum {
        MSI_FLAG_DEV_SYSFS              = (1 << 7),
        /* MSI-X entries must be contiguous */
        MSI_FLAG_MSIX_CONTIGUOUS        = (1 << 8),
+       /* Allocate simple MSI descriptors */
+       MSI_FLAG_ALLOC_SIMPLE_MSI_DESCS = (1 << 9),
+       /* Free MSI descriptors */
+       MSI_FLAG_FREE_MSI_DESCS         = (1 << 10),
 };
 
 int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,
--- a/kernel/irq/msi.c
+++ b/kernel/irq/msi.c
@@ -120,6 +120,32 @@ static int msi_add_simple_msi_descs(stru
 }
 
 /**
+ * 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);
+       }
+}
+
+/**
  * msi_device_has_property - Check whether a device has a specific MSI property
  * @dev:       Pointer to the device which is queried
  * @prop:      Property to check for
@@ -896,6 +922,16 @@ int __msi_domain_alloc_irqs(struct irq_d
        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
@@ -918,6 +954,10 @@ int msi_domain_alloc_irqs_descs_locked(s
 
        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;
@@ -979,6 +1019,13 @@ void __msi_domain_free_irqs(struct irq_d
        }
 }
 
+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
@@ -999,6 +1046,7 @@ void msi_domain_free_irqs_descs_locked(s
        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);
 }
 
 /**


Reply via email to