From nobody Mon Feb 9 00:00:55 2026 Received: from mail-pj1-f73.google.com (mail-pj1-f73.google.com [209.85.216.73]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B29C33195E3 for ; Thu, 29 Jan 2026 01:15:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.73 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769649356; cv=none; b=eUZ/9soshM0D2CxRbq/oM23G27lM7Alvuy00F02tS+ird7+d6Sp3cH/1KJibjPN4V2RtuSMzpoyz9iHNUexnNhvAkbZ4b0h9ays954hhP7vh0Jvuhd7tvqLuaJqmdFIhboEbh8xDXqH9q/c1jg+Og5NOQDpzbYKZGSuv9LQhW+o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1769649356; c=relaxed/simple; bh=ox2Up5FtQH0aplnsexm0ECraE0OqVPOftwajWnYeoZQ=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=QUY4zhr+bhm91HIMA4VzX5HxgRhTfYYjLttZ0NR0iX5ORdZ4Yg1fb0FEeJlP0MTvhHzOjU8cMLlK92CMmTcVMEt1ZhBCzZ0GAelSz9UK9twvh4MtejehJAob20xHJJRbR/EZFSjD071MwpU9BIDrCuNLUf+j/mUiuqwgbOTyodU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=QJYwc/Hh; arc=none smtp.client-ip=209.85.216.73 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--seanjc.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="QJYwc/Hh" Received: by mail-pj1-f73.google.com with SMTP id 98e67ed59e1d1-34c5d203988so729030a91.3 for ; Wed, 28 Jan 2026 17:15:50 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1769649350; x=1770254150; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:from:to:cc:subject:date:message-id:reply-to; bh=oUVgGQKjra+oTJtFOnUbyNE8ATML+3QU96XWRx/DAwg=; b=QJYwc/HhirWOQxQ6pimzwUjdLA7CNgdAbOk+6rAAOO8TgCjO8HQDHc60ppIJgS3S0R TDXhhOCDzeIiJ/ULldjN44FFuTAsmdROo3kPNcKFiEXC0L9tNL0lABC/FotZwbO2MSTp EPD1lI2dQy8Uobkr98JxCShw6kh77bTroQ602spQ0xOEYIp0IAmCfgFxs5T+Q8Z+dZ28 Udz1QawCPVtSKE3fOOs/tl+4h2GJ7+7o8u2EVz1VreNGtJzRykRXwSjqLRqD62LXf2CB EZLxs60PpqwxslczKa01wrLvJa1RpPcATCE5fqT4TExgDtTUy83jUAlZh1ys3aMWSLEZ M5oQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1769649350; x=1770254150; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:reply-to:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=oUVgGQKjra+oTJtFOnUbyNE8ATML+3QU96XWRx/DAwg=; b=dPmB3xPqN/fAw7Lr6YhXSp+TrAhXElE6BdfgwgJZrDKWFpds658zAKoqgM4/HxOEx8 uO1y9N9joEG+dYnOXis9Ow+6OLr+Y6XzCYy11zGNJAJothaQQhPvpc1S37lGlGjYvplc qZjl5+9MzRbOfveD9/j8mhE8gy8vqHdcUHDpwR5DoZGlh1/xM1Sd1L2I0+bfxhTEcvom HI2Zi/dDFb9L8kCgqDRHs7LZujdzbTU21Ri+Y8VCnyLizTuF4B2CGomUfy5owIbwinHD NzT4bpbEQOJRJ/N9JPxFnuXhpcbD6QBxFGTTBDobV2JxwcD50srU0rwWzWC3hlGmeqkL WpCg== X-Gm-Message-State: AOJu0YxJq/+pDJiPKdFD5Oo8c7EdzckXDZtvaa/I/X2J7xv0mODm6TXh 9TCinIljTg/7k4B1q7FjsYuFUkE+2rBjxZlQUOjdqzoTcGwlWy7tDGYABFdhjGRq4n8BI1ARzaZ e4USq4g== X-Received: from pjyl21.prod.google.com ([2002:a17:90a:ec15:b0:352:be9f:8324]) (user=seanjc job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90a:e704:b0:340:ff7d:c26 with SMTP id 98e67ed59e1d1-353fed0a12dmr7721418a91.16.1769649350136; Wed, 28 Jan 2026 17:15:50 -0800 (PST) Reply-To: Sean Christopherson Date: Wed, 28 Jan 2026 17:14:44 -0800 In-Reply-To: <20260129011517.3545883-1-seanjc@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20260129011517.3545883-1-seanjc@google.com> X-Mailer: git-send-email 2.53.0.rc1.217.geba53bf80e-goog Message-ID: <20260129011517.3545883-13-seanjc@google.com> Subject: [RFC PATCH v5 12/45] x86/virt/tdx: Simplify tdmr_get_pamt_sz() From: Sean Christopherson To: Thomas Gleixner , Ingo Molnar , Borislav Petkov , Dave Hansen , x86@kernel.org, Kiryl Shutsemau , Sean Christopherson , Paolo Bonzini Cc: linux-kernel@vger.kernel.org, linux-coco@lists.linux.dev, kvm@vger.kernel.org, Kai Huang , Rick Edgecombe , Yan Zhao , Vishal Annapurve , Ackerley Tng , Sagi Shahar , Binbin Wu , Xiaoyao Li , Isaku Yamahata Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Rick Edgecombe For each memory region that the TDX module might use (TDMR), the three separate PAMT allocations are needed. One for each supported page size (1GB, 2MB, 4KB). These store information on each page in the TDMR. In Linux, they are allocated out of one physically contiguous block, in order to more efficiently use some internal TDX module book keeping resources. So some simple math is needed to break the single large allocation into three smaller allocations for each page size. There are some commonalities in the math needed to calculate the base and size for each smaller allocation, and so an effort was made to share logic across the three. Unfortunately doing this turned out naturally tortured, with a loop iterating over the three page sizes, only to call into a function with a case statement for each page size. In the future Dynamic PAMT will add more logic that is special to the 4KB page size, making the benefit of the math sharing even more questionable. Three is not a very high number, so get rid of the loop and just duplicate the small calculation three times. In doing so, setup for future Dynamic PAMT changes and drop a net 33 lines of code. Since the loop that iterates over it is gone, further simplify the code by dropping the array of intermediate size and base storage. Just store the values to their final locations. Accept the small complication of having to clear tdmr->pamt_4k_base in the error path, so that tdmr_do_pamt_func() will not try to operate on the TDMR struct when attempting to free it. Signed-off-by: Rick Edgecombe Reviewed-by: Binbin Wu Tested-by: Sagi Shahar Signed-off-by: Sean Christopherson --- arch/x86/virt/vmx/tdx/tdx.c | 93 ++++++++++++------------------------- 1 file changed, 29 insertions(+), 64 deletions(-) diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 783bf704f2cd..0c4c873bff80 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -445,31 +445,21 @@ static int fill_out_tdmrs(struct list_head *tmb_list, * Calculate PAMT size given a TDMR and a page size. The returned * PAMT size is always aligned up to 4K page boundary. */ -static unsigned long tdmr_get_pamt_sz(struct tdmr_info *tdmr, int pgsz, - u16 pamt_entry_size) +static unsigned long tdmr_get_pamt_sz(struct tdmr_info *tdmr, int pgsz) { unsigned long pamt_sz, nr_pamt_entries; + const int tdx_pg_size_shift[] =3D { PAGE_SHIFT, PMD_SHIFT, PUD_SHIFT }; + const u16 pamt_entry_size[TDX_PS_NR] =3D { + tdx_sysinfo.tdmr.pamt_4k_entry_size, + tdx_sysinfo.tdmr.pamt_2m_entry_size, + tdx_sysinfo.tdmr.pamt_1g_entry_size, + }; =20 - switch (pgsz) { - case TDX_PS_4K: - nr_pamt_entries =3D tdmr->size >> PAGE_SHIFT; - break; - case TDX_PS_2M: - nr_pamt_entries =3D tdmr->size >> PMD_SHIFT; - break; - case TDX_PS_1G: - nr_pamt_entries =3D tdmr->size >> PUD_SHIFT; - break; - default: - WARN_ON_ONCE(1); - return 0; - } + nr_pamt_entries =3D tdmr->size >> tdx_pg_size_shift[pgsz]; + pamt_sz =3D nr_pamt_entries * pamt_entry_size[pgsz]; =20 - pamt_sz =3D nr_pamt_entries * pamt_entry_size; /* TDX requires PAMT size must be 4K aligned */ - pamt_sz =3D ALIGN(pamt_sz, PAGE_SIZE); - - return pamt_sz; + return PAGE_ALIGN(pamt_sz); } =20 /* @@ -507,28 +497,21 @@ static int tdmr_get_nid(struct tdmr_info *tdmr, struc= t list_head *tmb_list) * within @tdmr, and set up PAMTs for @tdmr. */ static int tdmr_set_up_pamt(struct tdmr_info *tdmr, - struct list_head *tmb_list, - u16 pamt_entry_size[]) + struct list_head *tmb_list) { - unsigned long pamt_base[TDX_PS_NR]; - unsigned long pamt_size[TDX_PS_NR]; - unsigned long tdmr_pamt_base; unsigned long tdmr_pamt_size; struct page *pamt; - int pgsz, nid; - + int nid; nid =3D tdmr_get_nid(tdmr, tmb_list); =20 /* * Calculate the PAMT size for each TDX supported page size * and the total PAMT size. */ - tdmr_pamt_size =3D 0; - for (pgsz =3D TDX_PS_4K; pgsz < TDX_PS_NR; pgsz++) { - pamt_size[pgsz] =3D tdmr_get_pamt_sz(tdmr, pgsz, - pamt_entry_size[pgsz]); - tdmr_pamt_size +=3D pamt_size[pgsz]; - } + tdmr->pamt_4k_size =3D tdmr_get_pamt_sz(tdmr, TDX_PS_4K); + tdmr->pamt_2m_size =3D tdmr_get_pamt_sz(tdmr, TDX_PS_2M); + tdmr->pamt_1g_size =3D tdmr_get_pamt_sz(tdmr, TDX_PS_1G); + tdmr_pamt_size =3D tdmr->pamt_4k_size + tdmr->pamt_2m_size + tdmr->pamt_1= g_size; =20 /* * Allocate one chunk of physically contiguous memory for all @@ -536,26 +519,18 @@ static int tdmr_set_up_pamt(struct tdmr_info *tdmr, * in overlapped TDMRs. */ pamt =3D alloc_contig_pages(tdmr_pamt_size >> PAGE_SHIFT, GFP_KERNEL, - nid, &node_online_map); - if (!pamt) + nid, &node_online_map); + if (!pamt) { + /* + * tdmr->pamt_4k_base is zero so the + * error path will skip freeing. + */ return -ENOMEM; - - /* - * Break the contiguous allocation back up into the - * individual PAMTs for each page size. - */ - tdmr_pamt_base =3D page_to_pfn(pamt) << PAGE_SHIFT; - for (pgsz =3D TDX_PS_4K; pgsz < TDX_PS_NR; pgsz++) { - pamt_base[pgsz] =3D tdmr_pamt_base; - tdmr_pamt_base +=3D pamt_size[pgsz]; } =20 - tdmr->pamt_4k_base =3D pamt_base[TDX_PS_4K]; - tdmr->pamt_4k_size =3D pamt_size[TDX_PS_4K]; - tdmr->pamt_2m_base =3D pamt_base[TDX_PS_2M]; - tdmr->pamt_2m_size =3D pamt_size[TDX_PS_2M]; - tdmr->pamt_1g_base =3D pamt_base[TDX_PS_1G]; - tdmr->pamt_1g_size =3D pamt_size[TDX_PS_1G]; + tdmr->pamt_4k_base =3D page_to_phys(pamt); + tdmr->pamt_2m_base =3D tdmr->pamt_4k_base + tdmr->pamt_4k_size; + tdmr->pamt_1g_base =3D tdmr->pamt_2m_base + tdmr->pamt_2m_size; =20 return 0; } @@ -586,10 +561,7 @@ static void tdmr_do_pamt_func(struct tdmr_info *tdmr, tdmr_get_pamt(tdmr, &pamt_base, &pamt_size); =20 /* Do nothing if PAMT hasn't been allocated for this TDMR */ - if (!pamt_size) - return; - - if (WARN_ON_ONCE(!pamt_base)) + if (!pamt_base) return; =20 pamt_func(pamt_base, pamt_size); @@ -615,14 +587,12 @@ static void tdmrs_free_pamt_all(struct tdmr_info_list= *tdmr_list) =20 /* Allocate and set up PAMTs for all TDMRs */ static int tdmrs_set_up_pamt_all(struct tdmr_info_list *tdmr_list, - struct list_head *tmb_list, - u16 pamt_entry_size[]) + struct list_head *tmb_list) { int i, ret =3D 0; =20 for (i =3D 0; i < tdmr_list->nr_consumed_tdmrs; i++) { - ret =3D tdmr_set_up_pamt(tdmr_entry(tdmr_list, i), tmb_list, - pamt_entry_size); + ret =3D tdmr_set_up_pamt(tdmr_entry(tdmr_list, i), tmb_list); if (ret) goto err; } @@ -903,18 +873,13 @@ static int construct_tdmrs(struct list_head *tmb_list, struct tdmr_info_list *tdmr_list, struct tdx_sys_info_tdmr *sysinfo_tdmr) { - u16 pamt_entry_size[TDX_PS_NR] =3D { - sysinfo_tdmr->pamt_4k_entry_size, - sysinfo_tdmr->pamt_2m_entry_size, - sysinfo_tdmr->pamt_1g_entry_size, - }; int ret; =20 ret =3D fill_out_tdmrs(tmb_list, tdmr_list); if (ret) return ret; =20 - ret =3D tdmrs_set_up_pamt_all(tdmr_list, tmb_list, pamt_entry_size); + ret =3D tdmrs_set_up_pamt_all(tdmr_list, tmb_list); if (ret) return ret; =20 --=20 2.53.0.rc1.217.geba53bf80e-goog