Received: by 2002:a25:868d:0:0:0:0:0 with SMTP id z13csp1418751ybk; Thu, 14 May 2020 08:31:20 -0700 (PDT) X-Google-Smtp-Source: ABdhPJwaN1szmgPA7Q44EVP3pkVtSqammb9IuUVlu8+FOtR6K0sMRUDOF2iq7sqvWXPO8zdHKulu X-Received: by 2002:a17:906:fb0e:: with SMTP id lz14mr4547374ejb.237.1589470279986; Thu, 14 May 2020 08:31:19 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1589470279; cv=none; d=google.com; s=arc-20160816; b=vA0JsIwJMB6b2+nO4lftrOruMHxw5/YyQOrGf5WPs+jLrHM5VpsSahuaH5AIYikypm JyXplDvKrVoLMrRzTJc3imX6tUYuuwaV0N5z+7mlKGf/B4yu7ODDPKgj9wPfJXqjq8VH sRDIyT5m6zoEmP2UVz6ILHsP1ibkpq2fcaksf/Ce0re1MJSisEcl2giaeD/EHyEzogM5 tL+erovO5s4VJmqXLeti/yC6uDjuoEFdQy8DYXGhm/wUKW5wNPeg7D55+cLybIKH1svs J4bWvq3Lsh3hHFglE1dReGjz2KaWJtgvAGM7oUtYHtTMiaUuzTldQty05/7hu5o/0LxZ IEYg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:user-agent:in-reply-to :content-disposition:mime-version:references:message-id:subject:cc :to:from:date; bh=Vjo97hF+gHfbaiKInUN3XRZxwOhkN5OM+/HWfR8oMd8=; b=y9siaBe5TvBHNjwD4TIqvadwhYEXkhIZv3TTG9wPKL11jfAE254C+e56NSIQq1oHhU yjKPPgUmUzb9DGLyt6ZBHADtGrURbPabStDn2lnwn9JzCu3kIoIWfFR5CP3vra1BBEjy lD+83vL4S2mU4qJmJGUhEsj7rAD2mYxdaHezFB2ADC23UwLnI/iSFjGwWC0oNy6HnVH2 aRQ7Dv2ci02urrsarpSc8N+9KNLNVaJHzZ1ipZkmcJ9J92Jym8+ETPfCshKUkaY9bUCz o6moyvAhrgoo2BNc91lpinqq3dogb6NETe8J3FChYlURpZ4G7agN2sU7LeUENh4skMJy YNgQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id h21si1816838edq.123.2020.05.14.08.30.55; Thu, 14 May 2020 08:31:19 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726492AbgENP2u (ORCPT + 99 others); Thu, 14 May 2020 11:28:50 -0400 Received: from foss.arm.com ([217.140.110.172]:38980 "EHLO foss.arm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726056AbgENP2u (ORCPT ); Thu, 14 May 2020 11:28:50 -0400 Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 67FDB1FB; Thu, 14 May 2020 08:28:49 -0700 (PDT) Received: from gaia (unknown [172.31.20.19]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 495F93F71E; Thu, 14 May 2020 08:28:47 -0700 (PDT) Date: Thu, 14 May 2020 16:28:40 +0100 From: Catalin Marinas To: Zhenyu Ye Cc: will@kernel.org, suzuki.poulose@arm.com, maz@kernel.org, steven.price@arm.com, guohanjun@huawei.com, olof@lixom.net, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org, linux-mm@kvack.org, arm@kernel.org, xiexiangyou@huawei.com, prime.zeng@hisilicon.com, zhangshaokun@hisilicon.com, kuhn.chenqun@huawei.com Subject: Re: [RFC PATCH v3 2/2] arm64: tlb: Use the TLBI RANGE feature in arm64 Message-ID: <20200514152840.GC1907@gaia> References: <20200414112835.1121-1-yezhenyu2@huawei.com> <20200414112835.1121-3-yezhenyu2@huawei.com> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20200414112835.1121-3-yezhenyu2@huawei.com> User-Agent: Mutt/1.10.1 (2018-07-13) Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Hi Zhenyu, On Tue, Apr 14, 2020 at 07:28:35PM +0800, Zhenyu Ye wrote: > diff --git a/arch/arm64/include/asm/tlb.h b/arch/arm64/include/asm/tlb.h > index b76df828e6b7..3a1816770bd1 100644 > --- a/arch/arm64/include/asm/tlb.h > +++ b/arch/arm64/include/asm/tlb.h > @@ -38,7 +38,12 @@ static inline void tlb_flush(struct mmu_gather *tlb) > return; > } > > - __flush_tlb_range(&vma, tlb->start, tlb->end, stride, last_level); > + if (cpus_have_const_cap(ARM64_HAS_TLBI_RANGE)) > + __flush_tlb_range_directly(&vma, tlb->start, tlb->end, > + stride, last_level); > + else > + __flush_tlb_range(&vma, tlb->start, tlb->end, > + stride, last_level); I think you could move such check in __flush_tlb_range() and avoid cpus_have_const_cap() in two places. More on this below. > diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h > index bc3949064725..a482188ea563 100644 > --- a/arch/arm64/include/asm/tlbflush.h > +++ b/arch/arm64/include/asm/tlbflush.h > @@ -59,6 +59,44 @@ > __ta; \ > }) > > +/* > + * This macro creates a properly formatted VA operand for the TLBI RANGE. > + * The value bit assignments are: > + * > + * +----------+------+-------+-------+-------+----------------------+ > + * | ASID | TG | SCALE | NUM | TTL | BADDR | > + * +-----------------+-------+-------+-------+----------------------+ > + * |63 48|47 46|45 44|43 39|38 37|36 0| > + * > + * The address range is determined by below formula: > + * [BADDR, BADDR + (NUM + 1) * 2^(5*SCALE + 1) * PAGESIZE) > + * > + */ > +#define __TLBI_VADDR_RANGE(addr, asid, tg, scale, num, ttl) \ > + ({ \ > + unsigned long __ta = (addr) >> PAGE_SHIFT; \ > + __ta &= GENMASK_ULL(36, 0); \ > + __ta |= (unsigned long)(ttl) << 37; \ > + __ta |= (unsigned long)(num) << 39; \ > + __ta |= (unsigned long)(scale) << 44; \ > + __ta |= (unsigned long)(tg) << 46; \ > + __ta |= (unsigned long)(asid) << 48; \ > + __ta; \ > + }) > + > +#define TLB_RANGE_MASK_SHIFT 5 > +#define TLB_RANGE_MASK GENMASK_ULL(TLB_RANGE_MASK_SHIFT - 1, 0) > + > +/* > + * __TG defines translation granule of the system, which is defined by > + * PAGE_SHIFT. Used by TTL. > + * - 4KB : 1 > + * - 16KB : 2 > + * - 64KB : 3 > + */ > +#define __TG ((PAGE_SHIFT - 12) / 2 + 1) I don't think we need __TLBI_VADDR_RANGE to take a tg argument since it's always the same. > + > + > /* > * TLB Invalidation > * ================ > @@ -171,12 +209,83 @@ static inline void flush_tlb_page(struct vm_area_struct *vma, > dsb(ish); > } > > +/* The maximum range size of one TLBI-RANGE instruction */ > +#define MAX_TLBI_RANGE_SIZE (1UL << 21) Nitpick: call this MAX_TLBI_RANGE_PAGES as that's not an address range. It may be useful to have a macro for the range here, something like: #define __TLBI_PAGES(num, scale) ((num + 1) << (5 * scale + 1)) and define MAX_TLBI_RANGE_PAGES in terms of this macro as __TLBI_PAGES(31, 3). > + > +/* > + * This interface uses the *rvale1is* instruction to flush TLBs > + * in [start, end) directly. > + * This instruction is supported from ARM v8.4. > + */ > +static inline void __flush_tlb_range_directly(struct vm_area_struct *vma, > + unsigned long start, unsigned long end, > + unsigned long stride, bool last_level) > +{ > + int num = 0; > + int scale = 0; > + unsigned long asid = ASID(vma->vm_mm); > + unsigned long addr = 0; > + unsigned long range_size; > + > + start = round_down(start, stride); > + end = round_up(end, stride); > + range_size = (end - start) >> PAGE_SHIFT; > + > + if (range_size > MAX_TLBI_RANGE_SIZE) { > + flush_tlb_mm(vma->vm_mm); > + return; > + } > + > + dsb(ishst); > + > + /* > + * The minimum size of TLB RANGE is 2 PAGE; > + * Use normal TLB instruction to handle odd PAGEs Nitpick: no need to capitalise PAGE. > + */ > + if (range_size % 2 == 1) { > + addr = __TLBI_VADDR(start, asid); > + if (last_level) { > + __tlbi(vale1is, addr); > + __tlbi_user(vale1is, addr); > + } else { > + __tlbi(vae1is, addr); > + __tlbi_user(vae1is, addr); > + } > + start += 1 << PAGE_SHIFT; > + range_size -= 1; > + } > + > + range_size >>= 1; > + while (range_size > 0) { > + num = (range_size & TLB_RANGE_MASK) - 1; > + if (num >= 0) { > + addr = __TLBI_VADDR_RANGE(start, asid, __TG, > + scale, num, 0); > + if (last_level) { > + __tlbi(rvale1is, addr); > + __tlbi_user(rvale1is, addr); > + } else { > + __tlbi(rvae1is, addr); > + __tlbi_user(rvae1is, addr); > + } > + start += (num + 1) << (5 * scale + 1) << PAGE_SHIFT; You could use the __TLBI_PAGES macro I proposed above. > + } > + scale++; > + range_size >>= TLB_RANGE_MASK_SHIFT; > + } So, you start from scale 0 and increment it until you reach the maximum. I think (haven't done the maths on paper) you could also start from the top with something like scale = ilog2(range_size) / 5. Not sure it's significantly better though, maybe avoiding the loop 3 times if your range is 2MB (which happens with huge pages). Anyway, I think it would be more efficient if we combine the __flush_tlb_range() and the _directly one into the same function with a single loop for both. For example, if the stride is 2MB already, we can handle this with a single classic TLBI without all the calculations for the range operation. The hardware may also handle this better since the software already told it there can be only one entry in that 2MB range. So each loop iteration could figure which operation to use based on cpucaps, TLBI range ops, stride and reduce range_size accordingly. -- Catalin