Message ID | 20231204105440.61448-13-ryan.roberts@arm.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:bcd1:0:b0:403:3b70:6f57 with SMTP id r17csp2678790vqy; Mon, 4 Dec 2023 02:56:39 -0800 (PST) X-Google-Smtp-Source: AGHT+IEbcRqhY6jY12Lcf558vcYQO/zfQNKw0Hc1zd/0NaU1XFhg2zHQnuTeicmk+pbPJs023rYX X-Received: by 2002:a05:6a00:8e02:b0:6ce:4e33:bb0 with SMTP id io2-20020a056a008e0200b006ce4e330bb0mr1161111pfb.49.1701687398856; Mon, 04 Dec 2023 02:56:38 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1701687398; cv=none; d=google.com; s=arc-20160816; b=nUeULXDV9gFXWvUSl2McrQSkQkR59pTkjY5sJxR/AHcPvjJ0gcYeLCUoq6gO9QfDGV 0ijOV9AEIK0psVXvUQQlrgb+Rm7EQAdq4YdOCDhVmwSfNb9526+1Qri4v9IGgv2nJPjM NN+6rPouuFVeDnBZwczBIgTUNV3EbRYyqU66+AuNdHPtTIZURU03BzwgfiFYjKR7UmzR O/WRgbshU1e8Db//Xqt5uQHq+KeV+Mjzm0IKn5VgYfzpAA7bk3rfz8UhGXMGz8WwUovA irhsY92E+Nk5hJljwHm9aWITzXtdYBzlMNvXhkFYIyTQUuzv1SfJMq9gnM8mhDBNM6tW 0veQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from; bh=mOqMiM5NGpNjoYnvzB47gVofKLzjpD8ExtOVjQRbqJI=; fh=a3gZESXuO1ptbCtzvzEnZL5xUl+WC4Vy5hoF2yaOXSs=; b=GR+cREeVSFEBE3a8TIA5KBMLb9s8N3GiBRztJFkO4hgm+qawSMsb6/pvsaA2KvxTHe ZRORQRnrAl0cdzWGyJ/zAQLLAzys/o5i05Rn78KPFKGetloVlDptMnW+WOLc3aQyExCv fd6j3+LO54sIIZIz1q51+iNZD2BK4YA2d0yPoR0qT2Y9zNHBFwlax1jHnq6myuEt2WZe a7jn1LvnuqulfQvQHpyacFT34oYFBOVeoaSYm4/2yQWnNR5fOfglP5ICAkx0zbEI7sGR NRIuyPgyIgcKQnwB+e2k6Zz75S4jTKymDW866kSYS+pwdC3NJkJyF8ixNVZw7RwzDC86 EowQ== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.31 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=arm.com Received: from morse.vger.email (morse.vger.email. [23.128.96.31]) by mx.google.com with ESMTPS id fh6-20020a056a00390600b006cbeeab7c0dsi7685282pfb.238.2023.12.04.02.56.38 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 04 Dec 2023 02:56:38 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.31 as permitted sender) client-ip=23.128.96.31; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.31 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=arm.com Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by morse.vger.email (Postfix) with ESMTP id 1F35D8078679; Mon, 4 Dec 2023 02:56:36 -0800 (PST) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.11 at morse.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344048AbjLDK4T (ORCPT <rfc822;chrisfriedt@gmail.com> + 99 others); Mon, 4 Dec 2023 05:56:19 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43984 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235563AbjLDKzn (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Mon, 4 Dec 2023 05:55:43 -0500 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 79F771720 for <linux-kernel@vger.kernel.org>; Mon, 4 Dec 2023 02:55:40 -0800 (PST) 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 7825816F2; Mon, 4 Dec 2023 02:56:27 -0800 (PST) Received: from e125769.cambridge.arm.com (e125769.cambridge.arm.com [10.1.196.26]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id C3DCA3F6C4; Mon, 4 Dec 2023 02:55:36 -0800 (PST) From: Ryan Roberts <ryan.roberts@arm.com> To: Catalin Marinas <catalin.marinas@arm.com>, Will Deacon <will@kernel.org>, Ard Biesheuvel <ardb@kernel.org>, Marc Zyngier <maz@kernel.org>, Oliver Upton <oliver.upton@linux.dev>, James Morse <james.morse@arm.com>, Suzuki K Poulose <suzuki.poulose@arm.com>, Zenghui Yu <yuzenghui@huawei.com>, Andrey Ryabinin <ryabinin.a.a@gmail.com>, Alexander Potapenko <glider@google.com>, Andrey Konovalov <andreyknvl@gmail.com>, Dmitry Vyukov <dvyukov@google.com>, Vincenzo Frascino <vincenzo.frascino@arm.com>, Andrew Morton <akpm@linux-foundation.org>, Anshuman Khandual <anshuman.khandual@arm.com>, Matthew Wilcox <willy@infradead.org>, Yu Zhao <yuzhao@google.com>, Mark Rutland <mark.rutland@arm.com>, David Hildenbrand <david@redhat.com>, Kefeng Wang <wangkefeng.wang@huawei.com>, John Hubbard <jhubbard@nvidia.com>, Zi Yan <ziy@nvidia.com>, Barry Song <21cnbao@gmail.com>, Alistair Popple <apopple@nvidia.com>, Yang Shi <shy828301@gmail.com> Cc: Ryan Roberts <ryan.roberts@arm.com>, linux-arm-kernel@lists.infradead.org, linux-mm@kvack.org, linux-kernel@vger.kernel.org Subject: [PATCH v3 12/15] arm64/mm: Split __flush_tlb_range() to elide trailing DSB Date: Mon, 4 Dec 2023 10:54:37 +0000 Message-Id: <20231204105440.61448-13-ryan.roberts@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231204105440.61448-1-ryan.roberts@arm.com> References: <20231204105440.61448-1-ryan.roberts@arm.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-0.8 required=5.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on morse.vger.email Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (morse.vger.email [0.0.0.0]); Mon, 04 Dec 2023 02:56:36 -0800 (PST) X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1784348565564580756 X-GMAIL-MSGID: 1784348565564580756 |
Series |
Transparent Contiguous PTEs for User Mappings
|
|
Commit Message
Ryan Roberts
Dec. 4, 2023, 10:54 a.m. UTC
Split __flush_tlb_range() into __flush_tlb_range_nosync() +
__flush_tlb_range(), in the same way as the existing flush_tlb_page()
arrangement. This allows calling __flush_tlb_range_nosync() to elide the
trailing DSB. Forthcoming "contpte" code will take advantage of this
when clearing the young bit from a contiguous range of ptes.
Signed-off-by: Ryan Roberts <ryan.roberts@arm.com>
---
arch/arm64/include/asm/tlbflush.h | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
Comments
On Mon, Dec 04, 2023 at 10:54:37AM +0000, Ryan Roberts wrote: > Split __flush_tlb_range() into __flush_tlb_range_nosync() + > __flush_tlb_range(), in the same way as the existing flush_tlb_page() > arrangement. This allows calling __flush_tlb_range_nosync() to elide the > trailing DSB. Forthcoming "contpte" code will take advantage of this > when clearing the young bit from a contiguous range of ptes. > > Signed-off-by: Ryan Roberts <ryan.roberts@arm.com> > --- > arch/arm64/include/asm/tlbflush.h | 13 +++++++++++-- > 1 file changed, 11 insertions(+), 2 deletions(-) > > diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h > index bb2c2833a987..925ef3bdf9ed 100644 > --- a/arch/arm64/include/asm/tlbflush.h > +++ b/arch/arm64/include/asm/tlbflush.h > @@ -399,7 +399,7 @@ do { \ > #define __flush_s2_tlb_range_op(op, start, pages, stride, tlb_level) \ > __flush_tlb_range_op(op, start, pages, stride, 0, tlb_level, false) > > -static inline void __flush_tlb_range(struct vm_area_struct *vma, > +static inline void __flush_tlb_range_nosync(struct vm_area_struct *vma, > unsigned long start, unsigned long end, > unsigned long stride, bool last_level, > int tlb_level) > @@ -431,10 +431,19 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma, > else > __flush_tlb_range_op(vae1is, start, pages, stride, asid, tlb_level, true); > > - dsb(ish); > mmu_notifier_arch_invalidate_secondary_tlbs(vma->vm_mm, start, end); > } > > +static inline void __flush_tlb_range(struct vm_area_struct *vma, > + unsigned long start, unsigned long end, > + unsigned long stride, bool last_level, > + int tlb_level) > +{ > + __flush_tlb_range_nosync(vma, start, end, stride, > + last_level, tlb_level); > + dsb(ish); > +} Hmm, are you sure it's safe to defer the DSB until after the secondary TLB invalidation? It will have a subtle effect on e.g. an SMMU participating in broadcast TLB maintenance, because now the ATC will be invalidated before completion of the TLB invalidation and it's not obviously safe to me. Will
On 12/12/2023 11:35, Will Deacon wrote: > On Mon, Dec 04, 2023 at 10:54:37AM +0000, Ryan Roberts wrote: >> Split __flush_tlb_range() into __flush_tlb_range_nosync() + >> __flush_tlb_range(), in the same way as the existing flush_tlb_page() >> arrangement. This allows calling __flush_tlb_range_nosync() to elide the >> trailing DSB. Forthcoming "contpte" code will take advantage of this >> when clearing the young bit from a contiguous range of ptes. >> >> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com> >> --- >> arch/arm64/include/asm/tlbflush.h | 13 +++++++++++-- >> 1 file changed, 11 insertions(+), 2 deletions(-) >> >> diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h >> index bb2c2833a987..925ef3bdf9ed 100644 >> --- a/arch/arm64/include/asm/tlbflush.h >> +++ b/arch/arm64/include/asm/tlbflush.h >> @@ -399,7 +399,7 @@ do { \ >> #define __flush_s2_tlb_range_op(op, start, pages, stride, tlb_level) \ >> __flush_tlb_range_op(op, start, pages, stride, 0, tlb_level, false) >> >> -static inline void __flush_tlb_range(struct vm_area_struct *vma, >> +static inline void __flush_tlb_range_nosync(struct vm_area_struct *vma, >> unsigned long start, unsigned long end, >> unsigned long stride, bool last_level, >> int tlb_level) >> @@ -431,10 +431,19 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma, >> else >> __flush_tlb_range_op(vae1is, start, pages, stride, asid, tlb_level, true); >> >> - dsb(ish); >> mmu_notifier_arch_invalidate_secondary_tlbs(vma->vm_mm, start, end); >> } >> >> +static inline void __flush_tlb_range(struct vm_area_struct *vma, >> + unsigned long start, unsigned long end, >> + unsigned long stride, bool last_level, >> + int tlb_level) >> +{ >> + __flush_tlb_range_nosync(vma, start, end, stride, >> + last_level, tlb_level); >> + dsb(ish); >> +} > > Hmm, are you sure it's safe to defer the DSB until after the secondary TLB > invalidation? It will have a subtle effect on e.g. an SMMU participating > in broadcast TLB maintenance, because now the ATC will be invalidated > before completion of the TLB invalidation and it's not obviously safe to me. I'll be honest; I don't know that it's safe. The notifier calls turned up during a rebase and I stared at it for a while, before eventually concluding that I should just follow the existing pattern in __flush_tlb_page_nosync(): That one calls the mmu notifier without the dsb, then flush_tlb_page() does the dsb after. So I assumed it was safe. If you think it's not safe, I guess there is a bug to fix in __flush_tlb_page_nosync()? > > Will
Hi Will, On 12/12/2023 11:47, Ryan Roberts wrote: > On 12/12/2023 11:35, Will Deacon wrote: >> On Mon, Dec 04, 2023 at 10:54:37AM +0000, Ryan Roberts wrote: >>> Split __flush_tlb_range() into __flush_tlb_range_nosync() + >>> __flush_tlb_range(), in the same way as the existing flush_tlb_page() >>> arrangement. This allows calling __flush_tlb_range_nosync() to elide the >>> trailing DSB. Forthcoming "contpte" code will take advantage of this >>> when clearing the young bit from a contiguous range of ptes. >>> >>> Signed-off-by: Ryan Roberts <ryan.roberts@arm.com> >>> --- >>> arch/arm64/include/asm/tlbflush.h | 13 +++++++++++-- >>> 1 file changed, 11 insertions(+), 2 deletions(-) >>> >>> diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h >>> index bb2c2833a987..925ef3bdf9ed 100644 >>> --- a/arch/arm64/include/asm/tlbflush.h >>> +++ b/arch/arm64/include/asm/tlbflush.h >>> @@ -399,7 +399,7 @@ do { \ >>> #define __flush_s2_tlb_range_op(op, start, pages, stride, tlb_level) \ >>> __flush_tlb_range_op(op, start, pages, stride, 0, tlb_level, false) >>> >>> -static inline void __flush_tlb_range(struct vm_area_struct *vma, >>> +static inline void __flush_tlb_range_nosync(struct vm_area_struct *vma, >>> unsigned long start, unsigned long end, >>> unsigned long stride, bool last_level, >>> int tlb_level) >>> @@ -431,10 +431,19 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma, >>> else >>> __flush_tlb_range_op(vae1is, start, pages, stride, asid, tlb_level, true); >>> >>> - dsb(ish); >>> mmu_notifier_arch_invalidate_secondary_tlbs(vma->vm_mm, start, end); >>> } >>> >>> +static inline void __flush_tlb_range(struct vm_area_struct *vma, >>> + unsigned long start, unsigned long end, >>> + unsigned long stride, bool last_level, >>> + int tlb_level) >>> +{ >>> + __flush_tlb_range_nosync(vma, start, end, stride, >>> + last_level, tlb_level); >>> + dsb(ish); >>> +} >> >> Hmm, are you sure it's safe to defer the DSB until after the secondary TLB >> invalidation? It will have a subtle effect on e.g. an SMMU participating >> in broadcast TLB maintenance, because now the ATC will be invalidated >> before completion of the TLB invalidation and it's not obviously safe to me. > > I'll be honest; I don't know that it's safe. The notifier calls turned up during > a rebase and I stared at it for a while, before eventually concluding that I > should just follow the existing pattern in __flush_tlb_page_nosync(): That one > calls the mmu notifier without the dsb, then flush_tlb_page() does the dsb > after. So I assumed it was safe. > > If you think it's not safe, I guess there is a bug to fix in > __flush_tlb_page_nosync()? Did you have an opinion on this? I'm just putting together a v4 of this series, and I'll remove this optimization if you think it's unsound. But in that case, I guess we have an existing bug to fix too? Thanks, Ryan > > > >> >> Will >
On Thu, Dec 14, 2023 at 11:53:52AM +0000, Ryan Roberts wrote: > On 12/12/2023 11:47, Ryan Roberts wrote: > > On 12/12/2023 11:35, Will Deacon wrote: > >> On Mon, Dec 04, 2023 at 10:54:37AM +0000, Ryan Roberts wrote: > >>> diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h > >>> index bb2c2833a987..925ef3bdf9ed 100644 > >>> --- a/arch/arm64/include/asm/tlbflush.h > >>> +++ b/arch/arm64/include/asm/tlbflush.h > >>> @@ -399,7 +399,7 @@ do { \ > >>> #define __flush_s2_tlb_range_op(op, start, pages, stride, tlb_level) \ > >>> __flush_tlb_range_op(op, start, pages, stride, 0, tlb_level, false) > >>> > >>> -static inline void __flush_tlb_range(struct vm_area_struct *vma, > >>> +static inline void __flush_tlb_range_nosync(struct vm_area_struct *vma, > >>> unsigned long start, unsigned long end, > >>> unsigned long stride, bool last_level, > >>> int tlb_level) > >>> @@ -431,10 +431,19 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma, > >>> else > >>> __flush_tlb_range_op(vae1is, start, pages, stride, asid, tlb_level, true); > >>> > >>> - dsb(ish); > >>> mmu_notifier_arch_invalidate_secondary_tlbs(vma->vm_mm, start, end); > >>> } > >>> > >>> +static inline void __flush_tlb_range(struct vm_area_struct *vma, > >>> + unsigned long start, unsigned long end, > >>> + unsigned long stride, bool last_level, > >>> + int tlb_level) > >>> +{ > >>> + __flush_tlb_range_nosync(vma, start, end, stride, > >>> + last_level, tlb_level); > >>> + dsb(ish); > >>> +} > >> > >> Hmm, are you sure it's safe to defer the DSB until after the secondary TLB > >> invalidation? It will have a subtle effect on e.g. an SMMU participating > >> in broadcast TLB maintenance, because now the ATC will be invalidated > >> before completion of the TLB invalidation and it's not obviously safe to me. > > > > I'll be honest; I don't know that it's safe. The notifier calls turned up during > > a rebase and I stared at it for a while, before eventually concluding that I > > should just follow the existing pattern in __flush_tlb_page_nosync(): That one > > calls the mmu notifier without the dsb, then flush_tlb_page() does the dsb > > after. So I assumed it was safe. > > > > If you think it's not safe, I guess there is a bug to fix in > > __flush_tlb_page_nosync()? > > Did you have an opinion on this? I'm just putting together a v4 of this series, > and I'll remove this optimization if you think it's unsound. But in that case, I > guess we have an existing bug to fix too? Sorry, Ryan, I've not had a chance to look into it in more detail. But as you rightly point out, you're not introducing the issue (assuming it is one), so I don't think it needs to hold you up. Your code just makes the thing more "obvious" to me. Robin, Jean-Philippe -- do we need to make sure that the SMMU has completed its TLB invalidation before issuing an ATC invalidate? My half-baked worry is whether or not an ATS request could refill the ATC before the TLBI has completed, therefore rendering the ATC invalidation useless. Will
On 2023-12-14 12:13 pm, Will Deacon wrote: > On Thu, Dec 14, 2023 at 11:53:52AM +0000, Ryan Roberts wrote: >> On 12/12/2023 11:47, Ryan Roberts wrote: >>> On 12/12/2023 11:35, Will Deacon wrote: >>>> On Mon, Dec 04, 2023 at 10:54:37AM +0000, Ryan Roberts wrote: >>>>> diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h >>>>> index bb2c2833a987..925ef3bdf9ed 100644 >>>>> --- a/arch/arm64/include/asm/tlbflush.h >>>>> +++ b/arch/arm64/include/asm/tlbflush.h >>>>> @@ -399,7 +399,7 @@ do { \ >>>>> #define __flush_s2_tlb_range_op(op, start, pages, stride, tlb_level) \ >>>>> __flush_tlb_range_op(op, start, pages, stride, 0, tlb_level, false) >>>>> >>>>> -static inline void __flush_tlb_range(struct vm_area_struct *vma, >>>>> +static inline void __flush_tlb_range_nosync(struct vm_area_struct *vma, >>>>> unsigned long start, unsigned long end, >>>>> unsigned long stride, bool last_level, >>>>> int tlb_level) >>>>> @@ -431,10 +431,19 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma, >>>>> else >>>>> __flush_tlb_range_op(vae1is, start, pages, stride, asid, tlb_level, true); >>>>> >>>>> - dsb(ish); >>>>> mmu_notifier_arch_invalidate_secondary_tlbs(vma->vm_mm, start, end); >>>>> } >>>>> >>>>> +static inline void __flush_tlb_range(struct vm_area_struct *vma, >>>>> + unsigned long start, unsigned long end, >>>>> + unsigned long stride, bool last_level, >>>>> + int tlb_level) >>>>> +{ >>>>> + __flush_tlb_range_nosync(vma, start, end, stride, >>>>> + last_level, tlb_level); >>>>> + dsb(ish); >>>>> +} >>>> >>>> Hmm, are you sure it's safe to defer the DSB until after the secondary TLB >>>> invalidation? It will have a subtle effect on e.g. an SMMU participating >>>> in broadcast TLB maintenance, because now the ATC will be invalidated >>>> before completion of the TLB invalidation and it's not obviously safe to me. >>> >>> I'll be honest; I don't know that it's safe. The notifier calls turned up during >>> a rebase and I stared at it for a while, before eventually concluding that I >>> should just follow the existing pattern in __flush_tlb_page_nosync(): That one >>> calls the mmu notifier without the dsb, then flush_tlb_page() does the dsb >>> after. So I assumed it was safe. >>> >>> If you think it's not safe, I guess there is a bug to fix in >>> __flush_tlb_page_nosync()? >> >> Did you have an opinion on this? I'm just putting together a v4 of this series, >> and I'll remove this optimization if you think it's unsound. But in that case, I >> guess we have an existing bug to fix too? > > Sorry, Ryan, I've not had a chance to look into it in more detail. But as > you rightly point out, you're not introducing the issue (assuming it is > one), so I don't think it needs to hold you up. Your code just makes the > thing more "obvious" to me. > > Robin, Jean-Philippe -- do we need to make sure that the SMMU has completed > its TLB invalidation before issuing an ATC invalidate? My half-baked worry > is whether or not an ATS request could refill the ATC before the TLBI > has completed, therefore rendering the ATC invalidation useless. I would agree, and the spec for CMD_ATC_INV does call out a TLBI->sync->ATCI->sync sequence. At the moment the SVA notifier is issuing its own command-based TLBIs anyway so the necessary sync is implicit there, but if and when we get BTM support wired up properly it would be nice not to have to bodge in an additional sync/DSB. Cheers, Robin.
On 14/12/2023 12:30, Robin Murphy wrote: > On 2023-12-14 12:13 pm, Will Deacon wrote: >> On Thu, Dec 14, 2023 at 11:53:52AM +0000, Ryan Roberts wrote: >>> On 12/12/2023 11:47, Ryan Roberts wrote: >>>> On 12/12/2023 11:35, Will Deacon wrote: >>>>> On Mon, Dec 04, 2023 at 10:54:37AM +0000, Ryan Roberts wrote: >>>>>> diff --git a/arch/arm64/include/asm/tlbflush.h >>>>>> b/arch/arm64/include/asm/tlbflush.h >>>>>> index bb2c2833a987..925ef3bdf9ed 100644 >>>>>> --- a/arch/arm64/include/asm/tlbflush.h >>>>>> +++ b/arch/arm64/include/asm/tlbflush.h >>>>>> @@ -399,7 +399,7 @@ do { \ >>>>>> #define __flush_s2_tlb_range_op(op, start, pages, stride, tlb_level) \ >>>>>> __flush_tlb_range_op(op, start, pages, stride, 0, tlb_level, false) >>>>>> -static inline void __flush_tlb_range(struct vm_area_struct *vma, >>>>>> +static inline void __flush_tlb_range_nosync(struct vm_area_struct *vma, >>>>>> unsigned long start, unsigned long end, >>>>>> unsigned long stride, bool last_level, >>>>>> int tlb_level) >>>>>> @@ -431,10 +431,19 @@ static inline void __flush_tlb_range(struct >>>>>> vm_area_struct *vma, >>>>>> else >>>>>> __flush_tlb_range_op(vae1is, start, pages, stride, asid, >>>>>> tlb_level, true); >>>>>> - dsb(ish); >>>>>> mmu_notifier_arch_invalidate_secondary_tlbs(vma->vm_mm, start, end); >>>>>> } >>>>>> +static inline void __flush_tlb_range(struct vm_area_struct *vma, >>>>>> + unsigned long start, unsigned long end, >>>>>> + unsigned long stride, bool last_level, >>>>>> + int tlb_level) >>>>>> +{ >>>>>> + __flush_tlb_range_nosync(vma, start, end, stride, >>>>>> + last_level, tlb_level); >>>>>> + dsb(ish); >>>>>> +} >>>>> >>>>> Hmm, are you sure it's safe to defer the DSB until after the secondary TLB >>>>> invalidation? It will have a subtle effect on e.g. an SMMU participating >>>>> in broadcast TLB maintenance, because now the ATC will be invalidated >>>>> before completion of the TLB invalidation and it's not obviously safe to me. >>>> >>>> I'll be honest; I don't know that it's safe. The notifier calls turned up >>>> during >>>> a rebase and I stared at it for a while, before eventually concluding that I >>>> should just follow the existing pattern in __flush_tlb_page_nosync(): That one >>>> calls the mmu notifier without the dsb, then flush_tlb_page() does the dsb >>>> after. So I assumed it was safe. >>>> >>>> If you think it's not safe, I guess there is a bug to fix in >>>> __flush_tlb_page_nosync()? >>> >>> Did you have an opinion on this? I'm just putting together a v4 of this series, >>> and I'll remove this optimization if you think it's unsound. But in that case, I >>> guess we have an existing bug to fix too? >> >> Sorry, Ryan, I've not had a chance to look into it in more detail. But as >> you rightly point out, you're not introducing the issue (assuming it is >> one), so I don't think it needs to hold you up. Your code just makes the >> thing more "obvious" to me. OK thanks. I'll leave my code as is for now then - that makes it easier to do A/B performance comparison with the existing code. And I can change it if/when mainline changes (presumably to add the dsb between the tlbi and the mmu notifier callback). >> >> Robin, Jean-Philippe -- do we need to make sure that the SMMU has completed >> its TLB invalidation before issuing an ATC invalidate? My half-baked worry >> is whether or not an ATS request could refill the ATC before the TLBI >> has completed, therefore rendering the ATC invalidation useless. > > I would agree, and the spec for CMD_ATC_INV does call out a > TLBI->sync->ATCI->sync sequence. At the moment the SVA notifier is issuing its > own command-based TLBIs anyway so the necessary sync is implicit there, but if > and when we get BTM support wired up properly it would be nice not to have to > bodge in an additional sync/DSB. > > Cheers, > Robin.
On Thu, Dec 14, 2023 at 12:30:55PM +0000, Robin Murphy wrote: > > Robin, Jean-Philippe -- do we need to make sure that the SMMU has completed > > its TLB invalidation before issuing an ATC invalidate? My half-baked worry > > is whether or not an ATS request could refill the ATC before the TLBI > > has completed, therefore rendering the ATC invalidation useless. > > I would agree, and the spec for CMD_ATC_INV does call out a > TLBI->sync->ATCI->sync sequence. At the moment the SVA notifier is issuing > its own command-based TLBIs anyway so the necessary sync is implicit there, > but if and when we get BTM support wired up properly it would be nice not to > have to bodge in an additional sync/DSB. Yes agreed, with BTM the CPU must call the notifier that issues ATC invalidation after completing the TLBI+DSB instructions. SMMU IHI0070F.a 3.9.1 ATS Interface Software must ensure that the SMMU TLB invalidation is complete before initiating the ATC invalidation. I'm guessing BTM will be enabled in the SMMU driver sometime soon, given that there already is one implementation in the wild that could use it. I think we didn't enable it because of the lack of separation between shared and private VMIDs, but that may now be solvable with the recent rework of the VMID allocator. Thanks, Jean
diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h index bb2c2833a987..925ef3bdf9ed 100644 --- a/arch/arm64/include/asm/tlbflush.h +++ b/arch/arm64/include/asm/tlbflush.h @@ -399,7 +399,7 @@ do { \ #define __flush_s2_tlb_range_op(op, start, pages, stride, tlb_level) \ __flush_tlb_range_op(op, start, pages, stride, 0, tlb_level, false) -static inline void __flush_tlb_range(struct vm_area_struct *vma, +static inline void __flush_tlb_range_nosync(struct vm_area_struct *vma, unsigned long start, unsigned long end, unsigned long stride, bool last_level, int tlb_level) @@ -431,10 +431,19 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma, else __flush_tlb_range_op(vae1is, start, pages, stride, asid, tlb_level, true); - dsb(ish); mmu_notifier_arch_invalidate_secondary_tlbs(vma->vm_mm, start, end); } +static inline void __flush_tlb_range(struct vm_area_struct *vma, + unsigned long start, unsigned long end, + unsigned long stride, bool last_level, + int tlb_level) +{ + __flush_tlb_range_nosync(vma, start, end, stride, + last_level, tlb_level); + dsb(ish); +} + static inline void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) {