From f001395855db2d04f499a2e2936f1d54dcaab225 Mon Sep 17 00:00:00 2001
From: Sam Shih <sam.shih@mediatek.com>
Date: Fri, 2 Jun 2023 13:06:24 +0800
Subject: [PATCH] [high-speed-io][999-2601-pcie-add-multi-MSI-support.patch]

---
 drivers/pci/controller/pcie-mediatek.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/pci/controller/pcie-mediatek.c b/drivers/pci/controller/pcie-mediatek.c
index db3672917..44a046005 100644
--- a/drivers/pci/controller/pcie-mediatek.c
+++ b/drivers/pci/controller/pcie-mediatek.c
@@ -440,24 +440,24 @@ static int mtk_pcie_irq_domain_alloc(struct irq_domain *domain, unsigned int vir
 				     unsigned int nr_irqs, void *args)
 {
 	struct mtk_pcie_port *port = domain->host_data;
-	unsigned long bit;
+	int bit, i;
 
-	WARN_ON(nr_irqs != 1);
 	mutex_lock(&port->lock);
 
-	bit = find_first_zero_bit(port->msi_irq_in_use, MTK_MSI_IRQS_NUM);
-	if (bit >= MTK_MSI_IRQS_NUM) {
+	bit = bitmap_find_free_region(port->msi_irq_in_use, MTK_MSI_IRQS_NUM,
+							order_base_2(nr_irqs));
+	if (bit < 0) {
 		mutex_unlock(&port->lock);
 		return -ENOSPC;
 	}
 
-	__set_bit(bit, port->msi_irq_in_use);
-
 	mutex_unlock(&port->lock);
 
-	irq_domain_set_info(domain, virq, bit, &mtk_msi_bottom_irq_chip,
-			    domain->host_data, handle_edge_irq,
-			    NULL, NULL);
+	for (i = 0; i < nr_irqs; i++) {
+		irq_domain_set_info(domain, virq + i, bit + i,
+				    &mtk_msi_bottom_irq_chip, domain->host_data,
+				    handle_edge_irq, NULL, NULL);
+	}
 
 	return 0;
 }
@@ -495,7 +495,7 @@ static struct irq_chip mtk_msi_irq_chip = {
 
 static struct msi_domain_info mtk_msi_domain_info = {
 	.flags	= (MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS |
-		   MSI_FLAG_PCI_MSIX),
+		   MSI_FLAG_PCI_MSIX | MSI_FLAG_MULTI_PCI_MSI),
 	.chip	= &mtk_msi_irq_chip,
 };
 
@@ -627,14 +627,14 @@ static void mtk_pcie_intr_handler(struct irq_desc *desc)
 		if (status & MSI_STATUS){
 			unsigned long imsi_status;
 
+			/* Clear MSI interrupt status */
+			writel(MSI_STATUS, port->base + PCIE_INT_STATUS);
 			while ((imsi_status = readl(port->base + PCIE_IMSI_STATUS))) {
 				for_each_set_bit(bit, &imsi_status, MTK_MSI_IRQS_NUM) {
 					virq = irq_find_mapping(port->inner_domain, bit);
 					generic_handle_irq(virq);
 				}
 			}
-			/* Clear MSI interrupt status */
-			writel(MSI_STATUS, port->base + PCIE_INT_STATUS);
 		}
 	}
 
-- 
2.34.1

