Message ID | 20240701095505.165383-9-steven.price@arm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | arm64: Support for running as a guest in Arm CCA | expand |
On Mon, Jul 01, 2024 at 10:54:58AM +0100, Steven Price wrote: > When __change_memory_common() is purely setting the valid bit on a PTE > (e.g. via the set_memory_valid() call) there is no need for a TLBI as > either the entry isn't changing (the valid bit was already set) or the > entry was invalid and so should not have been cached in the TLB. > > Signed-off-by: Steven Price <steven.price@arm.com> > --- > v4: New patch > --- > arch/arm64/mm/pageattr.c | 8 +++++++- > 1 file changed, 7 insertions(+), 1 deletion(-) > > diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c > index 0e270a1c51e6..547a9e0b46c2 100644 > --- a/arch/arm64/mm/pageattr.c > +++ b/arch/arm64/mm/pageattr.c > @@ -60,7 +60,13 @@ static int __change_memory_common(unsigned long start, unsigned long size, > ret = apply_to_page_range(&init_mm, start, size, change_page_range, > &data); > > - flush_tlb_kernel_range(start, start + size); > + /* > + * If the memory is being made valid without changing any other bits > + * then a TLBI isn't required as a non-valid entry cannot be cached in > + * the TLB. > + */ > + if (pgprot_val(set_mask) != PTE_VALID || pgprot_val(clear_mask)) > + flush_tlb_kernel_range(start, start + size); > return ret; Can you elaborate on when this actually happens, please? It feels like a case of "Doctor, it hurts when I do this" rather than something we should be trying to short-circuit in the low-level code. Will
On 09/07/2024 12:57, Will Deacon wrote: > On Mon, Jul 01, 2024 at 10:54:58AM +0100, Steven Price wrote: >> When __change_memory_common() is purely setting the valid bit on a PTE >> (e.g. via the set_memory_valid() call) there is no need for a TLBI as >> either the entry isn't changing (the valid bit was already set) or the >> entry was invalid and so should not have been cached in the TLB. >> >> Signed-off-by: Steven Price <steven.price@arm.com> >> --- >> v4: New patch >> --- >> arch/arm64/mm/pageattr.c | 8 +++++++- >> 1 file changed, 7 insertions(+), 1 deletion(-) >> >> diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c >> index 0e270a1c51e6..547a9e0b46c2 100644 >> --- a/arch/arm64/mm/pageattr.c >> +++ b/arch/arm64/mm/pageattr.c >> @@ -60,7 +60,13 @@ static int __change_memory_common(unsigned long start, unsigned long size, >> ret = apply_to_page_range(&init_mm, start, size, change_page_range, >> &data); >> >> - flush_tlb_kernel_range(start, start + size); >> + /* >> + * If the memory is being made valid without changing any other bits >> + * then a TLBI isn't required as a non-valid entry cannot be cached in >> + * the TLB. >> + */ >> + if (pgprot_val(set_mask) != PTE_VALID || pgprot_val(clear_mask)) >> + flush_tlb_kernel_range(start, start + size); >> return ret; > > Can you elaborate on when this actually happens, please? It feels like a > case of "Doctor, it hurts when I do this" rather than something we should > be trying to short-circuit in the low-level code. This is for the benefit of the following patch. When transitioning a page between shared and private we need to change the IPA (to set/clear the top bit). This requires a break-before-make - see __set_memory_enc_dec() in the following patch. The easiest way of implementing the code was to just call __change_memory_common() twice - once to make the entry invalid and then again to make it valid with the new IPA. But that led to a double TLBI which Catalin didn't like[1]. So this patch removes the unnecessary second TLBI by detecting that we're just making the entry valid. Or at least it would if I hadn't screwed up... I should have changed the following patch to ensure that the second call to __change_memory_common was only setting the PTE_VALID bit and not changing anything else (so that the TLBI could be skipped) and forgot to do that. So thanks for making me take a look at this again! Thanks, Steve [1] https://lore.kernel.org/lkml/Zmc3euO2YGh-g9Th@arm.com/
diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c index 0e270a1c51e6..547a9e0b46c2 100644 --- a/arch/arm64/mm/pageattr.c +++ b/arch/arm64/mm/pageattr.c @@ -60,7 +60,13 @@ static int __change_memory_common(unsigned long start, unsigned long size, ret = apply_to_page_range(&init_mm, start, size, change_page_range, &data); - flush_tlb_kernel_range(start, start + size); + /* + * If the memory is being made valid without changing any other bits + * then a TLBI isn't required as a non-valid entry cannot be cached in + * the TLB. + */ + if (pgprot_val(set_mask) != PTE_VALID || pgprot_val(clear_mask)) + flush_tlb_kernel_range(start, start + size); return ret; }
When __change_memory_common() is purely setting the valid bit on a PTE (e.g. via the set_memory_valid() call) there is no need for a TLBI as either the entry isn't changing (the valid bit was already set) or the entry was invalid and so should not have been cached in the TLB. Signed-off-by: Steven Price <steven.price@arm.com> --- v4: New patch --- arch/arm64/mm/pageattr.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)