Re: [PATCH v6 04/11] x86/virt/tdx: Allocate ref counts for Dynamic PAMT memory
From: Edgecombe, Rick P
Date: Wed Jul 08 2026 - 19:21:58 EST
On Wed, 2026-07-08 at 13:49 -0700, Sohil Mehta wrote:
> On 5/25/2026 7:35 PM, Rick Edgecombe wrote:
> > From: "Kirill A. Shutemov" <kirill.shutemov@xxxxxxxxxxxxxxx>
> >
> > The PAMT memory holds metadata for all possible TDX protected memory. Each
> > physical address range is covered by PAMT entries at three levels (1GB,
> > 2MB, 4KB). With Dynamic PAMT, the 4KB range of PAMT is allocated on
> > demand. The kernel supplies the TDX module with page pairs to store the
> > 4KB entries, which cover 2MB of host physical memory. The kernel must
> > provide this page pair before using pages from the range for TDX. If this
> > is not done, SEAMCALLs that give the pages to be protected by the TDX module
> > will fail.
> >
> > Allocate reference counters for every 2MB range to track TDX memory usage.
> > This can be used to handle concurrent get/put callers, in order to
> > accurately determine when the dynamic 4KB level of Dynamic PAMT needs to
> > be allocated and when it can be freed.
> >
> > This allocation will currently consume 2 MB for every 1 TB of address
> > space from 0 to max_pfn. The allocation size will depend on how the RAM is
> > physically laid out. In a worst case scenario where the entire 52-bit
> > address space is covered this would be 8GB. Then the DPAMT refcount
> > allocations could hypothetically cause the savings from Dynamic PAMT to go
> > negative on exotic platforms with sparse, small amounts of memory.
> >
>
> ...
>
> > +/*
> > + * On a machine with Dynamic PAMT, the kernel maintains a reference counter
> > + * for every 2M range.
>
> Commit log says every 2MB range.
Yea, I'll unify to MB, TB, KB.
>
> The counter indicates how many users there are for
> > + * the PAMT memory of the 2M range. The kernel allocates PAMT refcounts at
> > + * initialization.
> > + */
> > +static atomic_t *pamt_refcounts;
> > +
> > /* All TDX-usable memory regions. Protected by mem_hotplug_lock. */
> > static LIST_HEAD(tdx_memlist);
> >
> > @@ -254,6 +263,43 @@ static struct syscore tdx_syscore = {
> > .ops = &tdx_syscore_ops,
> > };
> >
> > +/*
> > + * Allocate PAMT reference counters for all physical memory.
> > + *
> > + * It consumes 2MiB for every 1TiB of physical memory.
>
> Commit log says 2MB and 1TB. I would make both consistent.
Yea, different authors for some of this text.
>
> > + */
> > +static int init_pamt_refcounts(void)
> > +{
> > + size_t size = DIV_ROUND_UP(max_pfn, PTRS_PER_PTE) * sizeof(*pamt_refcounts);
> > +
> > + if (!tdx_supports_dynamic_pamt(&tdx_sysinfo))
> > + return 0;
> > +
> > + pamt_refcounts = __vmalloc(size, GFP_KERNEL | __GFP_ZERO);
>
> vzalloc()?
Totally.
>
> > + if (!pamt_refcounts)
> > + return -ENOMEM;
> > +
> > + return 0;
> > +}
> > +
> > +static void free_pamt_refcounts(void)
> > +{
> > + if (!tdx_supports_dynamic_pamt(&tdx_sysinfo))
> > + return;
> > +
> > + vfree(pamt_refcounts);
> > + pamt_refcounts = NULL;
> > +}
> > +
> > +/* Find PAMT refcount for a given physical address */
>
> This comment is probably not that useful. The function name is
> descriptive by itself.
I'll delete it.
>
> > +static atomic_t * __maybe_unused tdx_find_pamt_refcount(unsigned long pfn)
> > +{
> > + /* Find which PMD a PFN is in. */
> > + unsigned long index = pfn >> (PMD_SHIFT - PAGE_SHIFT);
> > +
> > + return &pamt_refcounts[index];
> > +}
> > +