From patchwork Thu May 6 15:31:31 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?Pali_Roh=C3=A1r?= X-Patchwork-Id: 12242617 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-17.7 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI, SPF_HELO_NONE,SPF_PASS,URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4ACD0C433B4 for ; Thu, 6 May 2021 15:46:49 +0000 (UTC) Received: from desiato.infradead.org (desiato.infradead.org [90.155.92.199]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id D4765610A1 for ; Thu, 6 May 2021 15:46:48 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org D4765610A1 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=kernel.org Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:Cc:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=AwNqxR0XVGQKOMGeAndpaKM6EEMccyjbALti7o0+tAY=; b=Ysa9DTgDt6qgY2iB5mM1je2Oo 4I7j5UTnw4rJ7820/cuhEbwh/T1VK9PToNW2H2r79VUus9MXrlXOIL4bmwXv8OZ7sepGlKz/idS8t tHyV1e+F5h2ld0roB4HCyxeLtTeNQ49YeGoqUFt2y/w/cb97b1MDOf6s28AH2Zhg02FnzXy/Z0C4S w6yeCoRAy070njbmM2KcaF6sbXLxaMw2xxGiR27gM3YIp9kO3RZ2lD9wJTBFd2DlW8dSwSOVXskXA rgaDMpvjrZsA/5YNws4nasyh4RVNVmZhrYR1SPJevnU2rln/YZ4Wht4pGngf6Hsp7UCsqV8JS+E2m 6534qHR5w==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1legAm-004dyn-IC; Thu, 06 May 2021 15:44:21 +0000 Received: from bombadil.infradead.org ([2607:7c80:54:e::133]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1lefzp-004a7F-0r for linux-arm-kernel@desiato.infradead.org; Thu, 06 May 2021 15:33:02 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=bombadil.20210309; h=Content-Transfer-Encoding: Content-Type:MIME-Version:References:In-Reply-To:Message-Id:Date:Subject:Cc: To:From:Sender:Reply-To:Content-ID:Content-Description; bh=UDcVYQTqbz9OseTq0S0QydX4WFu/9YqW2MhPwXkVW/I=; b=VO3z1+vNWoxQ7OUL4AwXcd/ihp jroZ/QJzvaXlTOFLj3MCnbwQsL5L7w0cizJ3tWWwXtDFz/CFAuPNeQ0Mrw0msgxnWj6m9jbqFmsyo t6+527QZ2OaUVMWAmSs5eYUUWQkOX8uf/evEJ4D22ou9uUA3uyf8e+2+CAnkQHKAlENRP4F5tApp7 DKooVYaC32v9M3AQQ2dhF1x1iHdg5NxM51SP7U9pbFDXaqVf+pRKZQkS0XwPmx7C8fXlOC2yPLrKM sO6SIA+oJOQAEIF27oNhvwetvGoxp4k5t/0RJ8VMm0pZgYPa5ft74PFHZzuQK1Urum37tGi0fa/XM QHMIxqIQ==; Received: from mail.kernel.org ([198.145.29.99]) by bombadil.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1lefzi-0069lK-8A for linux-arm-kernel@lists.infradead.org; Thu, 06 May 2021 15:32:59 +0000 Received: by mail.kernel.org (Postfix) with ESMTPSA id 4E8C461434; Thu, 6 May 2021 15:32:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1620315170; bh=1sKdRSDWZQDgd5KUeWJnyAld8807tC29lRbcEtY4HEA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=UtD+5ok6KQaP3oZRK5I7CcxMyHMmBrBNWE1KRjfI+AKAaCu6riOACR2lQSooforV2 gU9Y7z2NUCjHFzIFvO2Xg+y697IoSWcxnLQZmSxeL1G5JBIG5W1FsH+afh4EzZc35x cJfVjZfzhbCL/VEvws1f9eG/vI6wycpWFbogUWxE+ErHS5BP7mqYy1WbeWppOlrrU2 cHDXRZpllZUTLswV6VuPVLeXQe3qBvEMdKpExhmZwrG2y7Lp7xJ05zGvsHkvrrZzzY SIrSLnqlsiSSHfd/VQTv79uYzRfEWLxpjbzpxC8+nmufhEE5AQIKTWnCnZVbzmS39o QseH1/RE0B01A== Received: by pali.im (Postfix) id 083448A1; Thu, 6 May 2021 17:32:50 +0200 (CEST) From: =?utf-8?q?Pali_Roh=C3=A1r?= To: Lorenzo Pieralisi , Thomas Petazzoni , Rob Herring , Bjorn Helgaas Cc: Russell King , =?utf-8?q?Marek_Beh=C3=BAn?= , Remi Pommarel , Xogium , Tomasz Maciej Nowak , Marc Zyngier , linux-pci@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org Subject: [PATCH 20/42] PCI: aardvark: Add support for more than 32 MSI interrupts Date: Thu, 6 May 2021 17:31:31 +0200 Message-Id: <20210506153153.30454-21-pali@kernel.org> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20210506153153.30454-1-pali@kernel.org> References: <20210506153153.30454-1-pali@kernel.org> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210506_083254_409640_86A55C66 X-CRM114-Status: GOOD ( 18.81 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Aardvark HW can handle MSI interrupt with any 16-bit number. Received MSI interrupt number is visible in PCIE_MSI_PAYLOAD_REG register after clearing corresponding bit in PCIE_MSI_STATUS_REG register. The first 32 interrupt numbers are currently stored in linear map in MSI inner domain. Store the rest in dynamic radix tree for space efficiency. Free interrupt numbers (available for MSI inner domain allocation) for the first 32 interrupts are currently stored in a bitmap. For the rest, introduce a linked list of allocated regions. In the most common scenario there is only one PCIe card connected on boards with Armada 3720 SoC. Since in Multi-MSI mode the PCIe device can use at most 32 interrupts, all these interrupts are allocated in the linear map of MSI inner domain and marked as used in the bitmap. For less common scenarios with PCIe devices with multiple functions or with a PCIe Bridge with packet switches with more connected PCIe devices more than 32 interrupts are requested. In this case, store each interrupt range from each interrupt request into the linked list as one node. In the worst case every PCIe function will occupy one node in this linked list. This change allows to use all 32 Multi-MSI interrupts on every connected PCIe card on the Turris Mox router with Mox G module. Signed-off-by: Pali Rohár Reviewed-by: Marek Behún --- drivers/pci/controller/pci-aardvark.c | 71 ++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 7 deletions(-) diff --git a/drivers/pci/controller/pci-aardvark.c b/drivers/pci/controller/pci-aardvark.c index 199015215779..d74e84b0e689 100644 --- a/drivers/pci/controller/pci-aardvark.c +++ b/drivers/pci/controller/pci-aardvark.c @@ -178,11 +178,18 @@ #define RETRAIN_WAIT_MAX_RETRIES 10 #define RETRAIN_WAIT_USLEEP_US 2000 -#define MSI_IRQ_NUM 32 +#define MSI_IRQ_LINEAR_COUNT 32 +#define MSI_IRQ_TOTAL_COUNT 65536 #define CFG_RD_UR_VAL 0xffffffff #define CFG_RD_CRS_VAL 0xffff0001 +struct advk_msi_range { + struct list_head list; + u16 first; + u16 count; +}; + struct advk_pcie { struct platform_device *pdev; void __iomem *base; @@ -193,7 +200,8 @@ struct advk_pcie { struct irq_chip msi_bottom_irq_chip; struct irq_chip msi_irq_chip; struct msi_domain_info msi_domain_info; - DECLARE_BITMAP(msi_used, MSI_IRQ_NUM); + DECLARE_BITMAP(msi_used_linear, MSI_IRQ_LINEAR_COUNT); + struct list_head msi_used_radix; struct mutex msi_used_lock; int link_gen; struct pci_bridge_emul bridge; @@ -885,12 +893,44 @@ static int advk_msi_irq_domain_alloc(struct irq_domain *domain, unsigned int nr_irqs, void *args) { struct advk_pcie *pcie = domain->host_data; + struct advk_msi_range *msi_range, *msi_range_prev, *msi_range_next; + unsigned int first, count, last; int hwirq, i; mutex_lock(&pcie->msi_used_lock); - hwirq = bitmap_find_free_region(pcie->msi_used, MSI_IRQ_NUM, + + /* First few used interrupt numbers are marked in bitmap (the most common) */ + hwirq = bitmap_find_free_region(pcie->msi_used_linear, MSI_IRQ_LINEAR_COUNT, order_base_2(nr_irqs)); + + /* And rest used interrupt numbers are stored in linked list as ranges */ + if (hwirq < 0) { + count = 1 << order_base_2(nr_irqs); + msi_range_prev = list_entry(&pcie->msi_used_radix, typeof(*msi_range), list); + do { + msi_range_next = list_next_entry(msi_range_prev, list); + last = list_entry_is_head(msi_range_next, &pcie->msi_used_radix, list) + ? MSI_IRQ_TOTAL_COUNT : msi_range_next->first; + first = list_entry_is_head(msi_range_prev, &pcie->msi_used_radix, list) + ? MSI_IRQ_LINEAR_COUNT : round_up(msi_range_prev->first + + msi_range_prev->count, count); + if (first + count > last) { + msi_range_prev = msi_range_next; + continue; + } + msi_range = kzalloc(sizeof(*msi_range), GFP_KERNEL); + if (msi_range) { + hwirq = first; + msi_range->first = first; + msi_range->count = count; + list_add(&msi_range->list, &msi_range_prev->list); + } + break; + } while (!list_entry_is_head(msi_range_next, &pcie->msi_used_radix, list)); + } + mutex_unlock(&pcie->msi_used_lock); + if (hwirq < 0) return -ENOSPC; @@ -908,9 +948,20 @@ static void advk_msi_irq_domain_free(struct irq_domain *domain, { struct irq_data *d = irq_domain_get_irq_data(domain, virq); struct advk_pcie *pcie = domain->host_data; + struct advk_msi_range *msi_range; mutex_lock(&pcie->msi_used_lock); - bitmap_release_region(pcie->msi_used, d->hwirq, order_base_2(nr_irqs)); + if (d->hwirq < MSI_IRQ_LINEAR_COUNT) { + bitmap_release_region(pcie->msi_used_linear, d->hwirq, order_base_2(nr_irqs)); + } else { + list_for_each_entry(msi_range, &pcie->msi_used_radix, list) { + if (msi_range->first != d->hwirq) + continue; + list_del(&msi_range->list); + kfree(msi_range); + break; + } + } mutex_unlock(&pcie->msi_used_lock); } @@ -967,6 +1018,7 @@ static int advk_pcie_init_msi_irq_domain(struct advk_pcie *pcie) struct msi_domain_info *msi_di; mutex_init(&pcie->msi_used_lock); + INIT_LIST_HEAD(&pcie->msi_used_radix); bottom_ic = &pcie->msi_bottom_irq_chip; @@ -982,9 +1034,14 @@ static int advk_pcie_init_msi_irq_domain(struct advk_pcie *pcie) MSI_FLAG_MULTI_PCI_MSI; msi_di->chip = msi_ic; + /* + * Aardvark HW can handle MSI interrupt with any 16bit number. + * For optimization first few interrupts are allocated in linear map + * (which is common scenario) and rest are allocated in radix tree. + */ pcie->msi_inner_domain = - irq_domain_add_linear(NULL, MSI_IRQ_NUM, - &advk_msi_domain_ops, pcie); + __irq_domain_add(NULL, MSI_IRQ_LINEAR_COUNT, MSI_IRQ_TOTAL_COUNT, 0, + &advk_msi_domain_ops, pcie); if (!pcie->msi_inner_domain) return -ENOMEM; @@ -1052,7 +1109,7 @@ static void advk_pcie_handle_msi(struct advk_pcie *pcie) msi_val = advk_readl(pcie, PCIE_MSI_STATUS_REG); msi_status = msi_val & ((~msi_mask) & PCIE_MSI_ALL_MASK); - for (msi_idx = 0; msi_idx < MSI_IRQ_NUM; msi_idx++) { + for (msi_idx = 0; msi_idx < BITS_PER_TYPE(msi_status); msi_idx++) { if (!(BIT(msi_idx) & msi_status)) continue;