Merge tag 'driver-core-6.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / drivers / base / platform-msi.c
index ca48d1f60865b1a397e8bc17cec3f953974275b8..11f5fdf65b9ef604ab574e476a1a09f89af24552 100644 (file)
@@ -13,6 +13,8 @@
 #include <linux/msi.h>
 #include <linux/slab.h>
 
+/* Begin of removal area. Once everything is converted over. Cleanup the includes too! */
+
 #define DEV_ID_SHIFT   21
 #define MAX_DEV_MSIS   (1 << (32 - DEV_ID_SHIFT))
 
@@ -204,8 +206,8 @@ static void platform_msi_free_priv_data(struct device *dev)
  * Returns:
  * Zero for success, or an error code in case of failure
  */
-int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec,
-                                  irq_write_msi_msg_t write_msi_msg)
+static int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec,
+                                         irq_write_msi_msg_t write_msi_msg)
 {
        int err;
 
@@ -219,18 +221,6 @@ int platform_msi_domain_alloc_irqs(struct device *dev, unsigned int nvec,
 
        return err;
 }
-EXPORT_SYMBOL_GPL(platform_msi_domain_alloc_irqs);
-
-/**
- * platform_msi_domain_free_irqs - Free MSI interrupts for @dev
- * @dev:       The device for which to free interrupts
- */
-void platform_msi_domain_free_irqs(struct device *dev)
-{
-       msi_domain_free_irqs_all(dev, MSI_DEFAULT_DOMAIN);
-       platform_msi_free_priv_data(dev);
-}
-EXPORT_SYMBOL_GPL(platform_msi_domain_free_irqs);
 
 /**
  * platform_msi_get_host_data - Query the private data associated with
@@ -350,3 +340,104 @@ int platform_msi_device_domain_alloc(struct irq_domain *domain, unsigned int vir
 
        return msi_domain_populate_irqs(domain->parent, dev, virq, nr_irqs, &data->arg);
 }
+
+/* End of removal area */
+
+/* Real per device domain interfaces */
+
+/*
+ * This indirection can go when platform_device_msi_init_and_alloc_irqs()
+ * is switched to a proper irq_chip::irq_write_msi_msg() callback. Keep it
+ * simple for now.
+ */
+static void platform_msi_write_msi_msg(struct irq_data *d, struct msi_msg *msg)
+{
+       irq_write_msi_msg_t cb = d->chip_data;
+
+       cb(irq_data_get_msi_desc(d), msg);
+}
+
+static void platform_msi_set_desc_byindex(msi_alloc_info_t *arg, struct msi_desc *desc)
+{
+       arg->desc = desc;
+       arg->hwirq = desc->msi_index;
+}
+
+static const struct msi_domain_template platform_msi_template = {
+       .chip = {
+               .name                   = "pMSI",
+               .irq_mask               = irq_chip_mask_parent,
+               .irq_unmask             = irq_chip_unmask_parent,
+               .irq_write_msi_msg      = platform_msi_write_msi_msg,
+               /* The rest is filled in by the platform MSI parent */
+       },
+
+       .ops = {
+               .set_desc               = platform_msi_set_desc_byindex,
+       },
+
+       .info = {
+               .bus_token              = DOMAIN_BUS_DEVICE_MSI,
+       },
+};
+
+/**
+ * platform_device_msi_init_and_alloc_irqs - Initialize platform device MSI
+ *                                          and allocate interrupts for @dev
+ * @dev:               The device for which to allocate interrupts
+ * @nvec:              The number of interrupts to allocate
+ * @write_msi_msg:     Callback to write an interrupt message for @dev
+ *
+ * Returns:
+ * Zero for success, or an error code in case of failure
+ *
+ * This creates a MSI domain on @dev which has @dev->msi.domain as
+ * parent. The parent domain sets up the new domain. The domain has
+ * a fixed size of @nvec. The domain is managed by devres and will
+ * be removed when the device is removed.
+ *
+ * Note: For migration purposes this falls back to the original platform_msi code
+ *      up to the point where all platforms have been converted to the MSI
+ *      parent model.
+ */
+int platform_device_msi_init_and_alloc_irqs(struct device *dev, unsigned int nvec,
+                                           irq_write_msi_msg_t write_msi_msg)
+{
+       struct irq_domain *domain = dev->msi.domain;
+
+       if (!domain || !write_msi_msg)
+               return -EINVAL;
+
+       /* Migration support. Will go away once everything is converted */
+       if (!irq_domain_is_msi_parent(domain))
+               return platform_msi_domain_alloc_irqs(dev, nvec, write_msi_msg);
+
+       /*
+        * @write_msi_msg is stored in the resulting msi_domain_info::data.
+        * The underlying domain creation mechanism will assign that
+        * callback to the resulting irq chip.
+        */
+       if (!msi_create_device_irq_domain(dev, MSI_DEFAULT_DOMAIN,
+                                         &platform_msi_template,
+                                         nvec, NULL, write_msi_msg))
+               return -ENODEV;
+
+       return msi_domain_alloc_irqs_range(dev, MSI_DEFAULT_DOMAIN, 0, nvec - 1);
+}
+EXPORT_SYMBOL_GPL(platform_device_msi_init_and_alloc_irqs);
+
+/**
+ * platform_device_msi_free_irqs_all - Free all interrupts for @dev
+ * @dev:       The device for which to free interrupts
+ */
+void platform_device_msi_free_irqs_all(struct device *dev)
+{
+       struct irq_domain *domain = dev->msi.domain;
+
+       msi_domain_free_irqs_all(dev, MSI_DEFAULT_DOMAIN);
+
+       /* Migration support. Will go away once everything is converted */
+       if (!irq_domain_is_msi_parent(domain))
+               platform_msi_free_priv_data(dev);
+}
+EXPORT_SYMBOL_GPL(platform_device_msi_free_irqs_all);