diff mbox series

[v4,3/5] arm64: Add support for FEAT_HAFT

Message ID 20241102104235.62560-4-yangyicong@huawei.com (mailing list archive)
State New, archived
Headers show
Series Support Armv8.9/v9.4 FEAT_HAFT | expand

Commit Message

Yicong Yang Nov. 2, 2024, 10:42 a.m. UTC
From: Yicong Yang <yangyicong@hisilicon.com>

Armv8.9/v9.4 introduces the feature Hardware managed Access Flag
for Table descriptors (FEAT_HAFT). The feature is indicated by
ID_AA64MMFR1_EL1.HAFDBS == 0b0011 and can be enabled by
TCR2_EL1.HAFT so it has a dependency on FEAT_TCR2.

Adds the Kconfig for FEAT_HAFT and support detecting and enabling
the feature. The feature is enabled in __cpu_setup() before MMU on
just like HA. A CPU capability is added to notify the user of the
feature.

Add definition of P{G,4,U,M}D_TABLE_AF bit and set the AF bit
when creating the page table, which will save the hardware
from having to update them at runtime. This will be ignored if
FEAT_HAFT is not enabled.

The AF bit of table descriptors cannot be managed by the software
per spec, unlike the HA. So this should be used only if it's supported
system wide by system_supports_haft().

Signed-off-by: Yicong Yang <yangyicong@hisilicon.com>
---
 arch/arm64/Kconfig                     | 15 +++++++++++++++
 arch/arm64/include/asm/cpufeature.h    |  6 ++++++
 arch/arm64/include/asm/pgalloc.h       | 12 +++++++-----
 arch/arm64/include/asm/pgtable-hwdef.h |  4 ++++
 arch/arm64/kernel/cpufeature.c         | 15 +++++++++++++++
 arch/arm64/mm/fixmap.c                 |  9 ++++++---
 arch/arm64/mm/mmu.c                    |  8 ++++----
 arch/arm64/mm/proc.S                   |  4 ++++
 arch/arm64/tools/cpucaps               |  1 +
 9 files changed, 62 insertions(+), 12 deletions(-)

Comments

Catalin Marinas Nov. 4, 2024, 5:28 p.m. UTC | #1
On Sat, Nov 02, 2024 at 06:42:33PM +0800, Yicong Yang wrote:
> diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
> index 3d261cc123c1..ed8c784ca082 100644
> --- a/arch/arm64/include/asm/cpufeature.h
> +++ b/arch/arm64/include/asm/cpufeature.h
> @@ -838,6 +838,12 @@ static inline bool system_supports_poe(void)
>  		alternative_has_cap_unlikely(ARM64_HAS_S1POE);
>  }
>  
> +static inline bool system_supports_haft(void)
> +{
> +	return IS_ENABLED(CONFIG_ARM64_HAFT) &&
> +		cpus_have_final_cap(ARM64_HAFT);
> +}

I'm fine with this approach. If we ever get hardware with mismatched
FEAT_HAFT and some secondary CPUs don't come up, we can revisit.

> diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
> index ccbae4525891..0bc88df7cb35 100644
> --- a/arch/arm64/mm/proc.S
> +++ b/arch/arm64/mm/proc.S
> @@ -498,6 +498,10 @@ alternative_else_nop_endif
>  	and	x9, x9, ID_AA64MMFR1_EL1_HAFDBS_MASK
>  	cbz	x9, 1f
>  	orr	tcr, tcr, #TCR_HA		// hardware Access flag update
> +
> +#ifdef CONFIG_ARM64_HAFT
> +	orr	tcr2, tcr2, TCR2_EL1x_HAFT
> +#endif /* CONFIG_ARM64_HAFT */
>  1:
>  #endif	/* CONFIG_ARM64_HW_AFDBM */
>  	msr	mair_el1, mair

If you still want #ifdefs, I'd have left it outside the HW_AFDBM. We
already have a dependency in the Kconfig. Anyway, I can fix this up.

I think as an additional patch we can also remove the ID checks for the
tcr bit in tge HW_AFDBM case. But that's unrelated to this series.
Yicong Yang Nov. 5, 2024, 2:47 a.m. UTC | #2
On 2024/11/5 1:28, Catalin Marinas wrote:
> On Sat, Nov 02, 2024 at 06:42:33PM +0800, Yicong Yang wrote:
>> diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
>> index 3d261cc123c1..ed8c784ca082 100644
>> --- a/arch/arm64/include/asm/cpufeature.h
>> +++ b/arch/arm64/include/asm/cpufeature.h
>> @@ -838,6 +838,12 @@ static inline bool system_supports_poe(void)
>>  		alternative_has_cap_unlikely(ARM64_HAS_S1POE);
>>  }
>>  
>> +static inline bool system_supports_haft(void)
>> +{
>> +	return IS_ENABLED(CONFIG_ARM64_HAFT) &&
>> +		cpus_have_final_cap(ARM64_HAFT);
>> +}
> 
> I'm fine with this approach. If we ever get hardware with mismatched
> FEAT_HAFT and some secondary CPUs don't come up, we can revisit.
> 
>> diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
>> index ccbae4525891..0bc88df7cb35 100644
>> --- a/arch/arm64/mm/proc.S
>> +++ b/arch/arm64/mm/proc.S
>> @@ -498,6 +498,10 @@ alternative_else_nop_endif
>>  	and	x9, x9, ID_AA64MMFR1_EL1_HAFDBS_MASK
>>  	cbz	x9, 1f
>>  	orr	tcr, tcr, #TCR_HA		// hardware Access flag update
>> +
>> +#ifdef CONFIG_ARM64_HAFT
>> +	orr	tcr2, tcr2, TCR2_EL1x_HAFT
>> +#endif /* CONFIG_ARM64_HAFT */
>>  1:
>>  #endif	/* CONFIG_ARM64_HW_AFDBM */
>>  	msr	mair_el1, mair
> 
> If you still want #ifdefs, I'd have left it outside the HW_AFDBM. We
> already have a dependency in the Kconfig. Anyway, I can fix this up.

yes it has already depend on the HW_AFDBM. And one asm won't cause much to the
Image size if user want CONFIG_ARM64_HAFT=n. I'll drop the #ifdef here.

> I think as an additional patch we can also remove the ID checks for the
> tcr bit in tge HW_AFDBM case. But that's unrelated to this series.

ok. I'll post a separate patch for dropping this.

Thanks.
Marc Zyngier Nov. 5, 2024, 8:35 a.m. UTC | #3
On Mon, 04 Nov 2024 17:28:48 +0000,
Catalin Marinas <catalin.marinas@arm.com> wrote:
> 
> On Sat, Nov 02, 2024 at 06:42:33PM +0800, Yicong Yang wrote:
> > diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
> > index 3d261cc123c1..ed8c784ca082 100644
> > --- a/arch/arm64/include/asm/cpufeature.h
> > +++ b/arch/arm64/include/asm/cpufeature.h
> > @@ -838,6 +838,12 @@ static inline bool system_supports_poe(void)
> >  		alternative_has_cap_unlikely(ARM64_HAS_S1POE);
> >  }
> >  
> > +static inline bool system_supports_haft(void)
> > +{
> > +	return IS_ENABLED(CONFIG_ARM64_HAFT) &&
> > +		cpus_have_final_cap(ARM64_HAFT);
> > +}
> 
> I'm fine with this approach. If we ever get hardware with mismatched
> FEAT_HAFT and some secondary CPUs don't come up, we can revisit.
> 
> > diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
> > index ccbae4525891..0bc88df7cb35 100644
> > --- a/arch/arm64/mm/proc.S
> > +++ b/arch/arm64/mm/proc.S
> > @@ -498,6 +498,10 @@ alternative_else_nop_endif
> >  	and	x9, x9, ID_AA64MMFR1_EL1_HAFDBS_MASK
> >  	cbz	x9, 1f
> >  	orr	tcr, tcr, #TCR_HA		// hardware Access flag update
> > +
> > +#ifdef CONFIG_ARM64_HAFT
> > +	orr	tcr2, tcr2, TCR2_EL1x_HAFT
> > +#endif /* CONFIG_ARM64_HAFT */
> >  1:
> >  #endif	/* CONFIG_ARM64_HW_AFDBM */
> >  	msr	mair_el1, mair
> 
> If you still want #ifdefs, I'd have left it outside the HW_AFDBM. We
> already have a dependency in the Kconfig. Anyway, I can fix this up.
> 
> I think as an additional patch we can also remove the ID checks for the
> tcr bit in tge HW_AFDBM case. But that's unrelated to this series.

I think you want to be careful with this one. I know of at least one
implementation that has a broken FEAT_HAFDBS implementation, that
removes it from the ID registers, but where the control bit in TCR_ELx
still takes effect.

Please see 6df696cd9bc1 ("arm64: errata: Mitigate Ampere1 erratum
AC03_CPU_38 at stage-2") which indicates how we actually rely on the
check for S1 translation.

Thanks,

	M.
Catalin Marinas Nov. 5, 2024, 9:58 a.m. UTC | #4
On Tue, Nov 05, 2024 at 08:35:51AM +0000, Marc Zyngier wrote:
> On Mon, 04 Nov 2024 17:28:48 +0000,
> Catalin Marinas <catalin.marinas@arm.com> wrote:
> > On Sat, Nov 02, 2024 at 06:42:33PM +0800, Yicong Yang wrote:
> > > diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
> > > index ccbae4525891..0bc88df7cb35 100644
> > > --- a/arch/arm64/mm/proc.S
> > > +++ b/arch/arm64/mm/proc.S
> > > @@ -498,6 +498,10 @@ alternative_else_nop_endif
> > >  	and	x9, x9, ID_AA64MMFR1_EL1_HAFDBS_MASK
> > >  	cbz	x9, 1f
> > >  	orr	tcr, tcr, #TCR_HA		// hardware Access flag update
> > > +
> > > +#ifdef CONFIG_ARM64_HAFT
> > > +	orr	tcr2, tcr2, TCR2_EL1x_HAFT
> > > +#endif /* CONFIG_ARM64_HAFT */
> > >  1:
> > >  #endif	/* CONFIG_ARM64_HW_AFDBM */
> > >  	msr	mair_el1, mair
> > 
> > If you still want #ifdefs, I'd have left it outside the HW_AFDBM. We
> > already have a dependency in the Kconfig. Anyway, I can fix this up.
> > 
> > I think as an additional patch we can also remove the ID checks for the
> > tcr bit in tge HW_AFDBM case. But that's unrelated to this series.
> 
> I think you want to be careful with this one. I know of at least one
> implementation that has a broken FEAT_HAFDBS implementation, that
> removes it from the ID registers, but where the control bit in TCR_ELx
> still takes effect.
> 
> Please see 6df696cd9bc1 ("arm64: errata: Mitigate Ampere1 erratum
> AC03_CPU_38 at stage-2") which indicates how we actually rely on the
> check for S1 translation.

Ah, thanks for this. So the hardware with the erratum above can still
update the pte after it has been marked invalid, hence we can't turn it
on in TCR_EL1 even if the rest of the kernel considers the feature
disabled. So yes, the HAFDBS code needs to stay as is.

Let's hope the hardware people learnt and we won't have similar errata
for FEAT_HAFT.
Yicong Yang Nov. 5, 2024, 10:38 a.m. UTC | #5
On 2024/11/5 10:47, Yicong Yang wrote:
> On 2024/11/5 1:28, Catalin Marinas wrote:
>> On Sat, Nov 02, 2024 at 06:42:33PM +0800, Yicong Yang wrote:
>>> diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
>>> index 3d261cc123c1..ed8c784ca082 100644
>>> --- a/arch/arm64/include/asm/cpufeature.h
>>> +++ b/arch/arm64/include/asm/cpufeature.h
>>> @@ -838,6 +838,12 @@ static inline bool system_supports_poe(void)
>>>  		alternative_has_cap_unlikely(ARM64_HAS_S1POE);
>>>  }
>>>  
>>> +static inline bool system_supports_haft(void)
>>> +{
>>> +	return IS_ENABLED(CONFIG_ARM64_HAFT) &&
>>> +		cpus_have_final_cap(ARM64_HAFT);
>>> +}
>>
>> I'm fine with this approach. If we ever get hardware with mismatched
>> FEAT_HAFT and some secondary CPUs don't come up, we can revisit.
>>
>>> diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
>>> index ccbae4525891..0bc88df7cb35 100644
>>> --- a/arch/arm64/mm/proc.S
>>> +++ b/arch/arm64/mm/proc.S
>>> @@ -498,6 +498,10 @@ alternative_else_nop_endif
>>>  	and	x9, x9, ID_AA64MMFR1_EL1_HAFDBS_MASK
>>>  	cbz	x9, 1f
>>>  	orr	tcr, tcr, #TCR_HA		// hardware Access flag update
>>> +
>>> +#ifdef CONFIG_ARM64_HAFT
>>> +	orr	tcr2, tcr2, TCR2_EL1x_HAFT
>>> +#endif /* CONFIG_ARM64_HAFT */
>>>  1:
>>>  #endif	/* CONFIG_ARM64_HW_AFDBM */
>>>  	msr	mair_el1, mair
>>
>> If you still want #ifdefs, I'd have left it outside the HW_AFDBM. We
>> already have a dependency in the Kconfig. Anyway, I can fix this up.
> 
> yes it has already depend on the HW_AFDBM. And one asm won't cause much to the
> Image size if user want CONFIG_ARM64_HAFT=n. I'll drop the #ifdef here.
> 

I rethink it and maybe we still need the #ifdef here considering one case: the hardware
supports FEAT_HAFT while user make CONFIG_ARM64_HAFT=n, in such case the HAFT will be
enabled unexpectedly if no CONFIG_ARM64_HAFT protection here.

Thanks.
Catalin Marinas Nov. 5, 2024, 10:54 a.m. UTC | #6
On Tue, Nov 05, 2024 at 06:38:51PM +0800, Yicong Yang wrote:
> On 2024/11/5 10:47, Yicong Yang wrote:
> > On 2024/11/5 1:28, Catalin Marinas wrote:
> >> On Sat, Nov 02, 2024 at 06:42:33PM +0800, Yicong Yang wrote:
> >>> diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
> >>> index 3d261cc123c1..ed8c784ca082 100644
> >>> --- a/arch/arm64/include/asm/cpufeature.h
> >>> +++ b/arch/arm64/include/asm/cpufeature.h
> >>> @@ -838,6 +838,12 @@ static inline bool system_supports_poe(void)
> >>>  		alternative_has_cap_unlikely(ARM64_HAS_S1POE);
> >>>  }
> >>>  
> >>> +static inline bool system_supports_haft(void)
> >>> +{
> >>> +	return IS_ENABLED(CONFIG_ARM64_HAFT) &&
> >>> +		cpus_have_final_cap(ARM64_HAFT);
> >>> +}
> >>
> >> I'm fine with this approach. If we ever get hardware with mismatched
> >> FEAT_HAFT and some secondary CPUs don't come up, we can revisit.
> >>
> >>> diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
> >>> index ccbae4525891..0bc88df7cb35 100644
> >>> --- a/arch/arm64/mm/proc.S
> >>> +++ b/arch/arm64/mm/proc.S
> >>> @@ -498,6 +498,10 @@ alternative_else_nop_endif
> >>>  	and	x9, x9, ID_AA64MMFR1_EL1_HAFDBS_MASK
> >>>  	cbz	x9, 1f
> >>>  	orr	tcr, tcr, #TCR_HA		// hardware Access flag update
> >>> +
> >>> +#ifdef CONFIG_ARM64_HAFT
> >>> +	orr	tcr2, tcr2, TCR2_EL1x_HAFT
> >>> +#endif /* CONFIG_ARM64_HAFT */
> >>>  1:
> >>>  #endif	/* CONFIG_ARM64_HW_AFDBM */
> >>>  	msr	mair_el1, mair
> >>
> >> If you still want #ifdefs, I'd have left it outside the HW_AFDBM. We
> >> already have a dependency in the Kconfig. Anyway, I can fix this up.
> > 
> > yes it has already depend on the HW_AFDBM. And one asm won't cause much to the
> > Image size if user want CONFIG_ARM64_HAFT=n. I'll drop the #ifdef here.
> > 
> 
> I rethink it and maybe we still need the #ifdef here considering one case: the hardware
> supports FEAT_HAFT while user make CONFIG_ARM64_HAFT=n, in such case the HAFT will be
> enabled unexpectedly if no CONFIG_ARM64_HAFT protection here.

Yes, still keeping the #ifdef but outside of HW_AFDBM. I can fix it up
myself when applying the patches.
Marc Zyngier Nov. 5, 2024, 11:52 a.m. UTC | #7
On Tue, 05 Nov 2024 09:58:26 +0000,
Catalin Marinas <catalin.marinas@arm.com> wrote:
> 
> On Tue, Nov 05, 2024 at 08:35:51AM +0000, Marc Zyngier wrote:
> > On Mon, 04 Nov 2024 17:28:48 +0000,
> > Catalin Marinas <catalin.marinas@arm.com> wrote:
> > > On Sat, Nov 02, 2024 at 06:42:33PM +0800, Yicong Yang wrote:
> > > > diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
> > > > index ccbae4525891..0bc88df7cb35 100644
> > > > --- a/arch/arm64/mm/proc.S
> > > > +++ b/arch/arm64/mm/proc.S
> > > > @@ -498,6 +498,10 @@ alternative_else_nop_endif
> > > >  	and	x9, x9, ID_AA64MMFR1_EL1_HAFDBS_MASK
> > > >  	cbz	x9, 1f
> > > >  	orr	tcr, tcr, #TCR_HA		// hardware Access flag update
> > > > +
> > > > +#ifdef CONFIG_ARM64_HAFT
> > > > +	orr	tcr2, tcr2, TCR2_EL1x_HAFT
> > > > +#endif /* CONFIG_ARM64_HAFT */
> > > >  1:
> > > >  #endif	/* CONFIG_ARM64_HW_AFDBM */
> > > >  	msr	mair_el1, mair
> > > 
> > > If you still want #ifdefs, I'd have left it outside the HW_AFDBM. We
> > > already have a dependency in the Kconfig. Anyway, I can fix this up.
> > > 
> > > I think as an additional patch we can also remove the ID checks for the
> > > tcr bit in tge HW_AFDBM case. But that's unrelated to this series.
> > 
> > I think you want to be careful with this one. I know of at least one
> > implementation that has a broken FEAT_HAFDBS implementation, that
> > removes it from the ID registers, but where the control bit in TCR_ELx
> > still takes effect.
> > 
> > Please see 6df696cd9bc1 ("arm64: errata: Mitigate Ampere1 erratum
> > AC03_CPU_38 at stage-2") which indicates how we actually rely on the
> > check for S1 translation.
> 
> Ah, thanks for this. So the hardware with the erratum above can still
> update the pte after it has been marked invalid, hence we can't turn it
> on in TCR_EL1 even if the rest of the kernel considers the feature
> disabled. So yes, the HAFDBS code needs to stay as is.

Indeed. Atomicity is overrated, let's go shopping.

> Let's hope the hardware people learnt and we won't have similar errata
> for FEAT_HAFT.

If I was religious, I'd light a candle. But we've both seen enough HW
to know that they *will* fsck it up. We just don't know how yet.

	M.
diff mbox series

Patch

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index fd9df6dcc593..7c023f3f55d6 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -2177,6 +2177,21 @@  config ARCH_PKEY_BITS
 	int
 	default 3
 
+config ARM64_HAFT
+	bool "Support for Hardware managed Access Flag for Table Descriptors"
+	depends on ARM64_HW_AFDBM
+	default y
+	help
+	  The ARMv8.9/ARMv9.5 introduces the feature Hardware managed Access
+	  Flag for Table descriptors. When enabled an architectural executed
+	  memory access will update the Access Flag in each Table descriptor
+	  which is accessed during the translation table walk and for which
+	  the Access Flag is 0. The Access Flag of the Table descriptor use
+	  the same bit of PTE_AF.
+
+	  The feature will only be enabled if all the CPUs in the system
+	  support this feature. If unsure, say Y.
+
 endmenu # "ARMv8.9 architectural features"
 
 config ARM64_SVE
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index 3d261cc123c1..ed8c784ca082 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -838,6 +838,12 @@  static inline bool system_supports_poe(void)
 		alternative_has_cap_unlikely(ARM64_HAS_S1POE);
 }
 
+static inline bool system_supports_haft(void)
+{
+	return IS_ENABLED(CONFIG_ARM64_HAFT) &&
+		cpus_have_final_cap(ARM64_HAFT);
+}
+
 int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt);
 bool try_emulate_mrs(struct pt_regs *regs, u32 isn);
 
diff --git a/arch/arm64/include/asm/pgalloc.h b/arch/arm64/include/asm/pgalloc.h
index 8ff5f2a2579e..e75422864d1b 100644
--- a/arch/arm64/include/asm/pgalloc.h
+++ b/arch/arm64/include/asm/pgalloc.h
@@ -28,7 +28,7 @@  static inline void __pud_populate(pud_t *pudp, phys_addr_t pmdp, pudval_t prot)
 
 static inline void pud_populate(struct mm_struct *mm, pud_t *pudp, pmd_t *pmdp)
 {
-	pudval_t pudval = PUD_TYPE_TABLE;
+	pudval_t pudval = PUD_TYPE_TABLE | PUD_TABLE_AF;
 
 	pudval |= (mm == &init_mm) ? PUD_TABLE_UXN : PUD_TABLE_PXN;
 	__pud_populate(pudp, __pa(pmdp), pudval);
@@ -50,7 +50,7 @@  static inline void __p4d_populate(p4d_t *p4dp, phys_addr_t pudp, p4dval_t prot)
 
 static inline void p4d_populate(struct mm_struct *mm, p4d_t *p4dp, pud_t *pudp)
 {
-	p4dval_t p4dval = P4D_TYPE_TABLE;
+	p4dval_t p4dval = P4D_TYPE_TABLE | P4D_TABLE_AF;
 
 	p4dval |= (mm == &init_mm) ? P4D_TABLE_UXN : P4D_TABLE_PXN;
 	__p4d_populate(p4dp, __pa(pudp), p4dval);
@@ -79,7 +79,7 @@  static inline void __pgd_populate(pgd_t *pgdp, phys_addr_t p4dp, pgdval_t prot)
 
 static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgdp, p4d_t *p4dp)
 {
-	pgdval_t pgdval = PGD_TYPE_TABLE;
+	pgdval_t pgdval = PGD_TYPE_TABLE | PGD_TABLE_AF;
 
 	pgdval |= (mm == &init_mm) ? PGD_TABLE_UXN : PGD_TABLE_PXN;
 	__pgd_populate(pgdp, __pa(p4dp), pgdval);
@@ -127,14 +127,16 @@  static inline void
 pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep)
 {
 	VM_BUG_ON(mm && mm != &init_mm);
-	__pmd_populate(pmdp, __pa(ptep), PMD_TYPE_TABLE | PMD_TABLE_UXN);
+	__pmd_populate(pmdp, __pa(ptep),
+		       PMD_TYPE_TABLE | PMD_TABLE_AF | PMD_TABLE_UXN);
 }
 
 static inline void
 pmd_populate(struct mm_struct *mm, pmd_t *pmdp, pgtable_t ptep)
 {
 	VM_BUG_ON(mm == &init_mm);
-	__pmd_populate(pmdp, page_to_phys(ptep), PMD_TYPE_TABLE | PMD_TABLE_PXN);
+	__pmd_populate(pmdp, page_to_phys(ptep),
+		       PMD_TYPE_TABLE | PMD_TABLE_AF | PMD_TABLE_PXN);
 }
 
 #endif
diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h
index fd330c1db289..c78a988cca93 100644
--- a/arch/arm64/include/asm/pgtable-hwdef.h
+++ b/arch/arm64/include/asm/pgtable-hwdef.h
@@ -99,6 +99,7 @@ 
 #define PGD_TYPE_TABLE		(_AT(pgdval_t, 3) << 0)
 #define PGD_TABLE_BIT		(_AT(pgdval_t, 1) << 1)
 #define PGD_TYPE_MASK		(_AT(pgdval_t, 3) << 0)
+#define PGD_TABLE_AF		(_AT(pgdval_t, 1) << 10)	/* Ignored if no FEAT_HAFT */
 #define PGD_TABLE_PXN		(_AT(pgdval_t, 1) << 59)
 #define PGD_TABLE_UXN		(_AT(pgdval_t, 1) << 60)
 
@@ -110,6 +111,7 @@ 
 #define P4D_TYPE_MASK		(_AT(p4dval_t, 3) << 0)
 #define P4D_TYPE_SECT		(_AT(p4dval_t, 1) << 0)
 #define P4D_SECT_RDONLY		(_AT(p4dval_t, 1) << 7)		/* AP[2] */
+#define P4D_TABLE_AF		(_AT(p4dval_t, 1) << 10)	/* Ignored if no FEAT_HAFT */
 #define P4D_TABLE_PXN		(_AT(p4dval_t, 1) << 59)
 #define P4D_TABLE_UXN		(_AT(p4dval_t, 1) << 60)
 
@@ -121,6 +123,7 @@ 
 #define PUD_TYPE_MASK		(_AT(pudval_t, 3) << 0)
 #define PUD_TYPE_SECT		(_AT(pudval_t, 1) << 0)
 #define PUD_SECT_RDONLY		(_AT(pudval_t, 1) << 7)		/* AP[2] */
+#define PUD_TABLE_AF		(_AT(pudval_t, 1) << 10)	/* Ignored if no FEAT_HAFT */
 #define PUD_TABLE_PXN		(_AT(pudval_t, 1) << 59)
 #define PUD_TABLE_UXN		(_AT(pudval_t, 1) << 60)
 
@@ -131,6 +134,7 @@ 
 #define PMD_TYPE_TABLE		(_AT(pmdval_t, 3) << 0)
 #define PMD_TYPE_SECT		(_AT(pmdval_t, 1) << 0)
 #define PMD_TABLE_BIT		(_AT(pmdval_t, 1) << 1)
+#define PMD_TABLE_AF		(_AT(pmdval_t, 1) << 10)	/* Ignored if no FEAT_HAFT */
 
 /*
  * Section
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 718728a85430..878712fa0d3b 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -2590,6 +2590,21 @@  static const struct arm64_cpu_capabilities arm64_features[] = {
 		.cpus = &dbm_cpus,
 		ARM64_CPUID_FIELDS(ID_AA64MMFR1_EL1, HAFDBS, DBM)
 	},
+#endif
+#ifdef CONFIG_ARM64_HAFT
+	{
+		.desc = "Hardware managed Access Flag for Table Descriptors",
+		/*
+		 * Contrary to the page/block access flag, the table access flag
+		 * cannot be emulated in software (no access fault will occur).
+		 * Therefore this should be used only if it's supported system
+		 * wide.
+		 */
+		.type = ARM64_CPUCAP_SYSTEM_FEATURE,
+		.capability = ARM64_HAFT,
+		.matches = has_cpuid_feature,
+		ARM64_CPUID_FIELDS(ID_AA64MMFR1_EL1, HAFDBS, HAFT)
+	},
 #endif
 	{
 		.desc = "CRC32 instructions",
diff --git a/arch/arm64/mm/fixmap.c b/arch/arm64/mm/fixmap.c
index de1e09d986ad..c5c5425791da 100644
--- a/arch/arm64/mm/fixmap.c
+++ b/arch/arm64/mm/fixmap.c
@@ -47,7 +47,8 @@  static void __init early_fixmap_init_pte(pmd_t *pmdp, unsigned long addr)
 
 	if (pmd_none(pmd)) {
 		ptep = bm_pte[BM_PTE_TABLE_IDX(addr)];
-		__pmd_populate(pmdp, __pa_symbol(ptep), PMD_TYPE_TABLE);
+		__pmd_populate(pmdp, __pa_symbol(ptep),
+			       PMD_TYPE_TABLE | PMD_TABLE_AF);
 	}
 }
 
@@ -59,7 +60,8 @@  static void __init early_fixmap_init_pmd(pud_t *pudp, unsigned long addr,
 	pmd_t *pmdp;
 
 	if (pud_none(pud))
-		__pud_populate(pudp, __pa_symbol(bm_pmd), PUD_TYPE_TABLE);
+		__pud_populate(pudp, __pa_symbol(bm_pmd),
+			       PUD_TYPE_TABLE | PUD_TABLE_AF);
 
 	pmdp = pmd_offset_kimg(pudp, addr);
 	do {
@@ -86,7 +88,8 @@  static void __init early_fixmap_init_pud(p4d_t *p4dp, unsigned long addr,
 	}
 
 	if (p4d_none(p4d))
-		__p4d_populate(p4dp, __pa_symbol(bm_pud), P4D_TYPE_TABLE);
+		__p4d_populate(p4dp, __pa_symbol(bm_pud),
+			       P4D_TYPE_TABLE | P4D_TABLE_AF);
 
 	pudp = pud_offset_kimg(p4dp, addr);
 	early_fixmap_init_pmd(pudp, addr, end);
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index e55b02fbddc8..6441a45eaeda 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -201,7 +201,7 @@  static void alloc_init_cont_pte(pmd_t *pmdp, unsigned long addr,
 
 	BUG_ON(pmd_sect(pmd));
 	if (pmd_none(pmd)) {
-		pmdval_t pmdval = PMD_TYPE_TABLE | PMD_TABLE_UXN;
+		pmdval_t pmdval = PMD_TYPE_TABLE | PMD_TABLE_UXN | PMD_TABLE_AF;
 		phys_addr_t pte_phys;
 
 		if (flags & NO_EXEC_MAPPINGS)
@@ -288,7 +288,7 @@  static void alloc_init_cont_pmd(pud_t *pudp, unsigned long addr,
 	 */
 	BUG_ON(pud_sect(pud));
 	if (pud_none(pud)) {
-		pudval_t pudval = PUD_TYPE_TABLE | PUD_TABLE_UXN;
+		pudval_t pudval = PUD_TYPE_TABLE | PUD_TABLE_UXN | PUD_TABLE_AF;
 		phys_addr_t pmd_phys;
 
 		if (flags & NO_EXEC_MAPPINGS)
@@ -333,7 +333,7 @@  static void alloc_init_pud(p4d_t *p4dp, unsigned long addr, unsigned long end,
 	pud_t *pudp;
 
 	if (p4d_none(p4d)) {
-		p4dval_t p4dval = P4D_TYPE_TABLE | P4D_TABLE_UXN;
+		p4dval_t p4dval = P4D_TYPE_TABLE | P4D_TABLE_UXN | P4D_TABLE_AF;
 		phys_addr_t pud_phys;
 
 		if (flags & NO_EXEC_MAPPINGS)
@@ -391,7 +391,7 @@  static void alloc_init_p4d(pgd_t *pgdp, unsigned long addr, unsigned long end,
 	p4d_t *p4dp;
 
 	if (pgd_none(pgd)) {
-		pgdval_t pgdval = PGD_TYPE_TABLE | PGD_TABLE_UXN;
+		pgdval_t pgdval = PGD_TYPE_TABLE | PGD_TABLE_UXN | PGD_TABLE_AF;
 		phys_addr_t p4d_phys;
 
 		if (flags & NO_EXEC_MAPPINGS)
diff --git a/arch/arm64/mm/proc.S b/arch/arm64/mm/proc.S
index ccbae4525891..0bc88df7cb35 100644
--- a/arch/arm64/mm/proc.S
+++ b/arch/arm64/mm/proc.S
@@ -498,6 +498,10 @@  alternative_else_nop_endif
 	and	x9, x9, ID_AA64MMFR1_EL1_HAFDBS_MASK
 	cbz	x9, 1f
 	orr	tcr, tcr, #TCR_HA		// hardware Access flag update
+
+#ifdef CONFIG_ARM64_HAFT
+	orr	tcr2, tcr2, TCR2_EL1x_HAFT
+#endif /* CONFIG_ARM64_HAFT */
 1:
 #endif	/* CONFIG_ARM64_HW_AFDBM */
 	msr	mair_el1, mair
diff --git a/arch/arm64/tools/cpucaps b/arch/arm64/tools/cpucaps
index eedb5acc21ed..b35004fa8313 100644
--- a/arch/arm64/tools/cpucaps
+++ b/arch/arm64/tools/cpucaps
@@ -56,6 +56,7 @@  HAS_TLB_RANGE
 HAS_VA52
 HAS_VIRT_HOST_EXTN
 HAS_WFXT
+HAFT
 HW_DBM
 KVM_HVHE
 KVM_PROTECTED_MODE