| From 8cbaa0879ccd4a3650aa693149196dc7fd4dd6de Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 10 Jan 2022 02:49:58 +0100 |
| Subject: PCI: aardvark: Fix support for MSI interrupts |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Pali Rohár <pali@kernel.org> |
| |
| [ Upstream commit b0b0b8b897f8e12b2368e868bd7cdc5742d5c5a9 ] |
| |
| Aardvark hardware supports Multi-MSI and MSI_FLAG_MULTI_PCI_MSI is already |
| set for the MSI chip. But when allocating MSI interrupt numbers for |
| Multi-MSI, the numbers need to be properly aligned, otherwise endpoint |
| devices send MSI interrupt with incorrect numbers. |
| |
| Fix this issue by using function bitmap_find_free_region() instead of |
| bitmap_find_next_zero_area(). |
| |
| To ensure that aligned MSI interrupt numbers are used by endpoint devices, |
| we cannot use Linux virtual irq numbers (as they are random and not |
| properly aligned). Instead we need to use the aligned hwirq numbers. |
| |
| This change fixes receiving MSI interrupts on Armada 3720 boards and |
| allows using NVMe disks which use Multi-MSI feature with 3 interrupts. |
| |
| Without this NVMe disks freeze booting as linux nvme-core.c is waiting |
| 60s for an interrupt. |
| |
| Link: https://lore.kernel.org/r/20220110015018.26359-4-kabel@kernel.org |
| Signed-off-by: Pali Rohár <pali@kernel.org> |
| Signed-off-by: Marek Behún <kabel@kernel.org> |
| Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/pci/controller/pci-aardvark.c | 16 ++++++---------- |
| 1 file changed, 6 insertions(+), 10 deletions(-) |
| |
| diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c |
| index a924564fdbbc..6277b3f3031a 100644 |
| --- a/drivers/pci/controller/pci-aardvark.c |
| +++ b/drivers/pci/controller/pci-aardvark.c |
| @@ -1179,7 +1179,7 @@ static void advk_msi_irq_compose_msi_msg(struct irq_data *data, |
| |
| msg->address_lo = lower_32_bits(msi_msg); |
| msg->address_hi = upper_32_bits(msi_msg); |
| - msg->data = data->irq; |
| + msg->data = data->hwirq; |
| } |
| |
| static int advk_msi_set_affinity(struct irq_data *irq_data, |
| @@ -1196,15 +1196,11 @@ static int advk_msi_irq_domain_alloc(struct irq_domain *domain, |
| int hwirq, i; |
| |
| mutex_lock(&pcie->msi_used_lock); |
| - hwirq = bitmap_find_next_zero_area(pcie->msi_used, MSI_IRQ_NUM, |
| - 0, nr_irqs, 0); |
| - if (hwirq >= MSI_IRQ_NUM) { |
| - mutex_unlock(&pcie->msi_used_lock); |
| - return -ENOSPC; |
| - } |
| - |
| - bitmap_set(pcie->msi_used, hwirq, nr_irqs); |
| + hwirq = bitmap_find_free_region(pcie->msi_used, MSI_IRQ_NUM, |
| + order_base_2(nr_irqs)); |
| mutex_unlock(&pcie->msi_used_lock); |
| + if (hwirq < 0) |
| + return -ENOSPC; |
| |
| for (i = 0; i < nr_irqs; i++) |
| irq_domain_set_info(domain, virq + i, hwirq + i, |
| @@ -1222,7 +1218,7 @@ static void advk_msi_irq_domain_free(struct irq_domain *domain, |
| struct advk_pcie *pcie = domain->host_data; |
| |
| mutex_lock(&pcie->msi_used_lock); |
| - bitmap_clear(pcie->msi_used, d->hwirq, nr_irqs); |
| + bitmap_release_region(pcie->msi_used, d->hwirq, order_base_2(nr_irqs)); |
| mutex_unlock(&pcie->msi_used_lock); |
| } |
| |
| -- |
| 2.35.1 |
| |