From patchwork Wed Sep 12 09:52:32 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Matthias Brugger X-Patchwork-Id: 10597253 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 25C0513BF for ; Wed, 12 Sep 2018 09:53:17 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 0FF0D2823E for ; Wed, 12 Sep 2018 09:53:17 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 01F1F283AF; Wed, 12 Sep 2018 09:53:16 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-2.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,MAILING_LIST_MULTI,RCVD_IN_DNSWL_NONE autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 578B12823E for ; Wed, 12 Sep 2018 09:53:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:Message-Id:Date: Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To: References:List-Owner; bh=iRwUemTWeYcveeD7219Q0lHLtKLP3arsPxtA8JotIVY=; b=AJ0 NN/eJaKAFuV0zPzmsw4zy09AQDgJrfWEYpAkQvX4qoomzlURhZMQpBUpNIX2r24lqnHIJ/1bcZopk WmYNx1c6yiFI3yQZxzgX8tjXS0JjuCnA4dkmsaeRrW8cT50hPwyx2hln8RInQ04Y0EX1gzdCAHsld u2CBrfJK1kMs1i1YE06cibJvS6jrNppKOl5Zy2DC3TXLaLzvsBbQWy7igi9zCvD7QD3YZPI+cshtU /6M1yqrAWE/wxX5bcwpCvKvLMhdRFIdPgvBRVMpBen2qMwKnV4SBZltbXHYYKv3mvE9S6d9bWqakW XgCEGjF1gl0QJ6uBAaRR5P1aGvWp+7w==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.90_1 #2 (Red Hat Linux)) id 1g01pb-00035G-1K; Wed, 12 Sep 2018 09:53:07 +0000 Received: from mail.kernel.org ([198.145.29.99]) by bombadil.infradead.org with esmtps (Exim 4.90_1 #2 (Red Hat Linux)) id 1g01pY-000340-3x for linux-arm-kernel@lists.infradead.org; Wed, 12 Sep 2018 09:53:05 +0000 Received: from ziggy.de (unknown [37.223.144.253]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id B2943204EC; Wed, 12 Sep 2018 09:52:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1536745972; bh=b1H5OQ+gG8L6XMUhr98Ih3aT9QGTSgjITBvtWTGY8rQ=; h=From:To:Cc:Subject:Date:From; b=jLrrWuhhOWpd4UzktITsX/Fmj1SiT+fUW4e1+NWrmE7DywCImNROvlyqbfeASej6f gyQE8x97wvYDpp3fbF03bcww1Rij4ZCOar3bVDB3pCtBLDTxR35nJykUXehyRM7zrB ilGZ1BU5TmA8EO+KIBZYFnDXZv9Lh1CIlWJQWvdw= From: matthias.bgg@kernel.org To: catalin.marinas@arm.com, will.deacon@arm.com, tglx@linutronix.de, jason@lakedaemon.net, marc.zyngier@arm.com, robert.richter@cavium.com Subject: [PATCH] irqchip/gic-v3-its: Add early memory allocation errata Date: Wed, 12 Sep 2018 11:52:32 +0200 Message-Id: <20180912095232.2110-1-matthias.bgg@kernel.org> X-Mailer: git-send-email 2.18.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20180912_025304_194093_BBE80769 X-CRM114-Status: GOOD ( 21.51 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Matthias Brugger , xiexiuqi@huawei.com, suzuki.poulose@arm.com, linux-kernel@vger.kernel.org, shankerd@codeaurora.org, matthias.bgg@gmail.com, Dave.Martin@arm.com, linux-arm-kernel@lists.infradead.org MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP From: Matthias Brugger Some hardware does not implement two-level page tables so that the amount of contigious memory needed by the baser is bigger then the zone order. This is a known problem on Cavium Thunderx with 4K page size. We fix this by adding an errata which allocates the memory early in the boot cycle, using the memblock allocator. Signed-off-by: Matthias Brugger --- arch/arm64/Kconfig | 12 ++++++++ arch/arm64/include/asm/cpucaps.h | 3 +- arch/arm64/kernel/cpu_errata.c | 33 +++++++++++++++++++++ drivers/irqchip/irq-gic-v3-its.c | 50 ++++++++++++++++++++------------ 4 files changed, 79 insertions(+), 19 deletions(-) diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 1b1a0e95c751..dfd9fe08f0b2 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -597,6 +597,18 @@ config QCOM_FALKOR_ERRATUM_E1041 If unsure, say Y. +config CAVIUM_ALLOC_ITS_TABLE_EARLY + bool "Cavium Thunderx: Allocate the its table early" + default y + depends on ARM64_4K_PAGES && FORCE_MAX_ZONEORDER < 13 + depends on ARM_GIC_V3_ITS + help + Cavium Thunderx needs to allocate 16MB of ITS translation table. + This can be bigger as MAX_ZONE_ORDER and need therefore be done + via the memblock allocator. + + If unsure, say Y. + endmenu diff --git a/arch/arm64/include/asm/cpucaps.h b/arch/arm64/include/asm/cpucaps.h index ae1f70450fb2..c98be4809b7f 100644 --- a/arch/arm64/include/asm/cpucaps.h +++ b/arch/arm64/include/asm/cpucaps.h @@ -51,7 +51,8 @@ #define ARM64_SSBD 30 #define ARM64_MISMATCHED_CACHE_TYPE 31 #define ARM64_HAS_STAGE2_FWB 32 +#define ARM64_WORKAROUND_CAVIUM_ITS_TABLE 33 -#define ARM64_NCAPS 33 +#define ARM64_NCAPS 34 #endif /* __ASM_CPUCAPS_H */ diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c index dec10898d688..7908f8fa3ba8 100644 --- a/arch/arm64/kernel/cpu_errata.c +++ b/arch/arm64/kernel/cpu_errata.c @@ -411,6 +411,29 @@ static bool has_ssbd_mitigation(const struct arm64_cpu_capabilities *entry, } #endif /* CONFIG_ARM64_SSBD */ +#ifdef CONFIG_CAVIUM_ALLOC_ITS_TABLE_EARLY +#include +extern void *its_base; + +/* + * Hardware that doesn't use two-level page table and exceedes + * the maximum order of pages that can be allocated by the buddy + * allocator. Try to use the memblock allocator instead. + * This has been observed on Cavium Thunderx machines with 4K + * page size. + */ +static bool __init its_early_alloc(const struct arm64_cpu_capabilities *cap, + int scope) +{ + /* We need to allocate the table only once */ + if (scope & ARM64_CPUCAP_SCOPE_BOOT_CPU && !its_base) + its_base = (void *)memblock_virt_alloc_nopanic(16 * SZ_1M, + 64 * SZ_1K); + + return true; +} +#endif /* CONFIG_CAVIUM_ALLOC_ITS_TABLE_EARLY */ + #define CAP_MIDR_RANGE(model, v_min, r_min, v_max, r_max) \ .matches = is_affected_midr_range, \ .midr_range = MIDR_RANGE(model, v_min, r_min, v_max, r_max) @@ -679,6 +702,16 @@ const struct arm64_cpu_capabilities arm64_errata[] = { .type = ARM64_CPUCAP_LOCAL_CPU_ERRATUM, .matches = has_ssbd_mitigation, }, +#endif +#ifdef CONFIG_CAVIUM_ALLOC_ITS_TABLE_EARLY + { + /* Cavium ThunderX, pass 1.x - 2.1 */ + .desc = "Cavium alloc ITS table early", + .capability = ARM64_WORKAROUND_CAVIUM_ITS_TABLE, + .type = ARM64_CPUCAP_SCOPE_BOOT_CPU, + .matches = its_early_alloc, + .midr_range = MIDR_RANGE(MIDR_THUNDERX, 0, 0, 1, 1), + }, #endif { } diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c index c2df341ff6fa..b78546740a0d 100644 --- a/drivers/irqchip/irq-gic-v3-its.c +++ b/drivers/irqchip/irq-gic-v3-its.c @@ -87,6 +87,8 @@ struct its_baser { u32 psz; }; +void *its_base; + struct its_device; /* @@ -1666,7 +1668,7 @@ static void its_write_baser(struct its_node *its, struct its_baser *baser, baser->val = its_read_baser(its, baser); } -static int its_setup_baser(struct its_node *its, struct its_baser *baser, +static int __init its_setup_baser(struct its_node *its, struct its_baser *baser, u64 cache, u64 shr, u32 psz, u32 order, bool indirect) { @@ -1675,7 +1677,6 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser, u64 type = GITS_BASER_TYPE(val); u64 baser_phys, tmp; u32 alloc_pages; - void *base; retry_alloc_baser: alloc_pages = (PAGE_ORDER_TO_SIZE(order) / psz); @@ -1687,11 +1688,22 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser, order = get_order(GITS_BASER_PAGES_MAX * psz); } - base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, order); - if (!base) - return -ENOMEM; + if (cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_ITS_TABLE)) { + if (!its_base) { + pr_warn("ITS@%pa: %s Allocation using memblock failed %pS\n", + &its->phys_base, its_base_type_string[type], + its_base); + return -ENOMEM; + } + + } else { + its_base = (void *)__get_free_pages(GFP_KERNEL | __GFP_ZERO, + order); + if (!its_base) + return -ENOMEM; + } - baser_phys = virt_to_phys(base); + baser_phys = virt_to_phys(its_base); /* Check if the physical address of the memory is above 48bits */ if (IS_ENABLED(CONFIG_ARM64_64K_PAGES) && (baser_phys >> 48)) { @@ -1699,7 +1711,7 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser, /* 52bit PA is supported only when PageSize=64K */ if (psz != SZ_64K) { pr_err("ITS: no 52bit PA support when psz=%d\n", psz); - free_pages((unsigned long)base, order); + free_pages((unsigned long)its_base, order); return -ENXIO; } @@ -1744,7 +1756,7 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser, shr = tmp & GITS_BASER_SHAREABILITY_MASK; if (!shr) { cache = GITS_BASER_nC; - gic_flush_dcache_to_poc(base, PAGE_ORDER_TO_SIZE(order)); + gic_flush_dcache_to_poc(its_base, PAGE_ORDER_TO_SIZE(order)); } goto retry_baser; } @@ -1755,7 +1767,7 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser, * size and retry. If we reach 4K, then * something is horribly wrong... */ - free_pages((unsigned long)base, order); + free_pages((unsigned long)its_base, order); baser->base = NULL; switch (psz) { @@ -1772,19 +1784,19 @@ static int its_setup_baser(struct its_node *its, struct its_baser *baser, pr_err("ITS@%pa: %s doesn't stick: %llx %llx\n", &its->phys_base, its_base_type_string[type], val, tmp); - free_pages((unsigned long)base, order); + free_pages((unsigned long)its_base, order); return -ENXIO; } baser->order = order; - baser->base = base; + baser->base = its_base; baser->psz = psz; tmp = indirect ? GITS_LVL1_ENTRY_SIZE : esz; pr_info("ITS@%pa: allocated %d %s @%lx (%s, esz %d, psz %dK, shr %d)\n", &its->phys_base, (int)(PAGE_ORDER_TO_SIZE(order) / (int)tmp), its_base_type_string[type], - (unsigned long)virt_to_phys(base), + (unsigned long)virt_to_phys(its_base), indirect ? "indirect" : "flat", (int)esz, psz / SZ_1K, (int)shr >> GITS_BASER_SHAREABILITY_SHIFT); @@ -1832,12 +1844,14 @@ static bool its_parse_indirect_baser(struct its_node *its, * feature is not supported by hardware. */ new_order = max_t(u32, get_order(esz << ids), new_order); - if (new_order >= MAX_ORDER) { - new_order = MAX_ORDER - 1; - ids = ilog2(PAGE_ORDER_TO_SIZE(new_order) / (int)esz); - pr_warn("ITS@%pa: %s Table too large, reduce ids %u->%u\n", - &its->phys_base, its_base_type_string[type], - its->device_ids, ids); + if (!cpus_have_const_cap(ARM64_WORKAROUND_CAVIUM_ITS_TABLE)) { + if (new_order >= MAX_ORDER) { + new_order = MAX_ORDER - 1; + ids = ilog2(PAGE_ORDER_TO_SIZE(new_order) / (int)esz); + pr_warn("ITS@%pa: %s Table too large, reduce ids %u->%u\n", + &its->phys_base, its_base_type_string[type], + its->device_ids, ids); + } } *order = new_order;