struct irq_domain;
 struct irq_domain_ops;
 struct irq_chip;
+struct irq_fwspec;
 struct device_node;
 struct fwnode_handle;
 struct msi_domain_info;
  *                     function.
  * @msi_post_free:     Optional function which is invoked after freeing
  *                     all interrupts.
+ * @msi_translate:     Optional translate callback to support the odd wire to
+ *                     MSI bridges, e.g. MBIGEN
  *
  * @get_hwirq, @msi_init and @msi_free are callbacks used by the underlying
  * irqdomain.
                                            struct device *dev);
        void            (*msi_post_free)(struct irq_domain *domain,
                                         struct device *dev);
+       int             (*msi_translate)(struct irq_domain *domain, struct irq_fwspec *fwspec,
+                                        irq_hw_number_t *hwirq, unsigned int *type);
 };
 
 /**
 
        irq_domain_free_irqs_top(domain, virq, nr_irqs);
 }
 
+static int msi_domain_translate(struct irq_domain *domain, struct irq_fwspec *fwspec,
+                               irq_hw_number_t *hwirq, unsigned int *type)
+{
+       struct msi_domain_info *info = domain->host_data;
+
+       /*
+        * This will catch allocations through the regular irqdomain path except
+        * for MSI domains which really support this, e.g. MBIGEN.
+        */
+       if (!info->ops->msi_translate)
+               return -ENOTSUPP;
+       return info->ops->msi_translate(domain, fwspec, hwirq, type);
+}
+
 static const struct irq_domain_ops msi_domain_ops = {
        .alloc          = msi_domain_alloc,
        .free           = msi_domain_free,
        .activate       = msi_domain_activate,
        .deactivate     = msi_domain_deactivate,
+       .translate      = msi_domain_translate,
 };
 
 static irq_hw_number_t msi_domain_ops_get_hwirq(struct msi_domain_info *info,