[PATCH] LoongArch: mm: Define DIRECT_MAP_PHYSMEM_END

Huacai Chen chenhuacai at kernel.org
Tue Aug 11 07:41:23 PDT 2026


Hi, Han,

On Tue, Aug 11, 2026 at 7:58 PM Han Gao <gaohan at iscas.ac.cn> wrote:
>
> get_free_mem_region() and mhp_get_pluggable_range() bound their
> search to DIRECT_MAP_PHYSMEM_END.  LoongArch does not define it, so
> the fallback in include/linux/mm.h applies: under
> CONFIG_SPARSEMEM_VMEMMAP it is (1ULL << MAX_PHYSMEM_BITS) - 1, a
> compile-time constant that does not adapt to the physical address
> bits of the CPU (cpu_pabits, probed from CPUCFG1: 48 on
> 3A5000/3A6000, 47 on 3C6000, 40 on the 2K series).
As far as I know, Loongson-3C6000 is also PA48.

>
> The vmemmap window only covers physical space below 2^(cpu_pabits+1)
> (VMEMMAP_SIZE), so on CPUs with fewer than 48 physical address bits
> get_free_mem_region() may hand ZONE_DEVICE a region with no struct
> page backing:
>
> - On the 2K series the region returned at the top of the 48-bit
>   physical space is outside the vmemmap window; vmemmap_populate()
>   wraps the range around and maps it into low memory, silently
>   corrupting the page tables.
> - On 3C6000 the vmemmap range of the region's last section used to
>   end exactly at 2^64 and wrap to 0, leaving vmemmap_populate() with
>   nothing to map, so memmap_init_zone_device() faulted while writing
>   struct page (reported with amdkfd on 6.16 [1]).  Commit 2969b42c8f99
>   ("LoongArch/mm: align vmemmap to maximal folio size") moved the
>   vmemmap base down by one PMD, which keeps that section in bounds on
>   current 3C6000 configs, but the 2K series is still affected and the
>   3C6000 case only holds for the current vmemmap layout.
>
> Define DIRECT_MAP_PHYSMEM_END as (1ULL << cpu_pabits) - 1 so that
> both searches stay within the vmemmap-covered physical space,
> mirroring commit f3336b48cf9d ("riscv: mm: Define
> DIRECT_MAP_PHYSMEM_END").
>
> [1] https://lore.kernel.org/amd-gfx/20250814032153.227285-1-jeffbai@aosc.io/
>
> Cc: stable at vger.kernel.org # v6.13+
> Signed-off-by: Han Gao <gaohan at iscas.ac.cn>
> ---
>  arch/loongarch/include/asm/pgtable.h | 7 +++++++
>  1 file changed, 7 insertions(+)
>
> diff --git a/arch/loongarch/include/asm/pgtable.h b/arch/loongarch/include/asm/pgtable.h
> index 223528c04d73..244931e4bc58 100644
> --- a/arch/loongarch/include/asm/pgtable.h
> +++ b/arch/loongarch/include/asm/pgtable.h
> @@ -125,6 +125,13 @@ struct vm_area_struct;
>
>  #endif
>
> +/* Needed to limit get_free_mem_region() */
> +#if defined(CONFIG_FLATMEM) || defined(CONFIG_SPARSEMEM_VMEMMAP)
> +#define DIRECT_MAP_PHYSMEM_END ((1ULL << cpu_pabits) - 1)
> +#elif defined(CONFIG_SPARSEMEM)
> +/* DIRECT_MAP_PHYSMEM_END is not limited by VA space assignment in this case */
> +#endif
 ((1ULL << cpu_pabits) - 1) is not always smaller than  (1ULL <<
MAX_PHYSMEM_BITS) - 1.

So I think a better way is:
+#ifndef CONFIG_SPARSEMEM
+#define DIRECT_MAP_PHYSMEM_END (((1ULL << (cpu_pabits + 1)) - 1)
+#else
+#define DIRECT_MAP_PHYSMEM_END MIN(((1ULL << (cpu_pabits + 1) - 1,
(1ULL << MAX_PHYSMEM_BITS) - 1)
+#endif

Huacai

> +
>  #define ptep_get(ptep) READ_ONCE(*(ptep))
>  #define pmdp_get(pmdp) READ_ONCE(*(pmdp))
>
> --
> 2.47.3
>



More information about the linux-riscv mailing list