All of lore.kernel.org
 help / color / mirror / Atom feed
From: Marc Zyngier <maz@kernel.org>
To: Nianyao Tang <tangnianyao@huawei.com>
Cc: <tglx@linutronix.de>, <linux-kernel@vger.kernel.org>,
	<linux-arm-kernel@lists.infradead.org>, <guoyang2@huawei.com>,
	<wangwudi@hisilicon.com>
Subject: Re: [PATCH] irqchip/gic-v4.1:Check whether indirect table is supported in allocate_vpe_l1_table
Date: Mon, 22 Jan 2024 09:00:22 +0000	[thread overview]
Message-ID: <86sf2p91zt.wl-maz@kernel.org> (raw)
In-Reply-To: <20240122160607.1078960-1-tangnianyao@huawei.com>

[Fixing the LKML address, which has bits of Stephan's address embedded
in it...]

On Mon, 22 Jan 2024 16:06:07 +0000,
Nianyao Tang <tangnianyao@huawei.com> wrote:
> 
> In allocate_vpe_l1_table, when we fail to inherit VPE table from other
> redistributors or ITSs, and we allocate a new vpe table for current common 
> affinity field without checking whether indirect table is supported.
> Let's fix it.

Is there an actual implementation that doesn't support the indirect
property for the VPE table? I know this is allowed for consistency
with the original revision of the architecture, but I never expected
an actual GICv4.1 implementation to be *that* bad.

If that's the case, I'm a bit puzzled/worried.

> 
> Signed-off-by: Nianyao Tang <tangnianyao@huawei.com>
> ---
>  drivers/irqchip/irq-gic-v3-its.c   | 28 ++++++++++++++++++++++------
>  include/linux/irqchip/arm-gic-v3.h |  1 +
>  2 files changed, 23 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
> index d097001c1e3e..4146d1e285ec 100644
> --- a/drivers/irqchip/irq-gic-v3-its.c
> +++ b/drivers/irqchip/irq-gic-v3-its.c
> @@ -2836,6 +2836,7 @@ static int allocate_vpe_l1_table(void)
>  	unsigned int psz = SZ_64K;
>  	unsigned int np, epp, esz;
>  	struct page *page;
> +	bool indirect = false;

Why the upfront initialisation?

>  
>  	if (!gic_rdists->has_rvpeid)
>  		return 0;
> @@ -2890,6 +2891,12 @@ static int allocate_vpe_l1_table(void)
>  		break;
>  	}
>  
> +	/* probe the indirect */
> +	val = GICR_VPROPBASER_4_1_INDIRECT;
> +	gicr_write_vpropbaser(val, vlpi_base + GICR_VPROPBASER);
> +	val = gicr_read_vpropbaser(vlpi_base + GICR_VPROPBASER);
> +	indirect = !!(val & GICR_VPROPBASER_4_1_INDIRECT);

You can probe the indirect bit as part of the page-size probe, no need
for an extra R/W sequence.

> +
>  	/*
>  	 * Start populating the register from scratch, including RO fields
>  	 * (which we want to print in debug cases...)
> @@ -2907,15 +2914,24 @@ static int allocate_vpe_l1_table(void)
>  	 * as indirect and compute the number of required L1 pages.
>  	 */
>  	if (epp < ITS_MAX_VPEID) {
> -		int nl2;
> +		if (indirect) {
> +			int nl2;
>  
> -		val |= GICR_VPROPBASER_4_1_INDIRECT;
> +			val |= GICR_VPROPBASER_4_1_INDIRECT;
>  
> -		/* Number of L2 pages required to cover the VPEID space */
> -		nl2 = DIV_ROUND_UP(ITS_MAX_VPEID, epp);
> +			/* Number of L2 pages required to cover the VPEID space */
> +			nl2 = DIV_ROUND_UP(ITS_MAX_VPEID, epp);
>  
> -		/* Number of L1 pages to point to the L2 pages */
> -		npg = DIV_ROUND_UP(nl2 * SZ_8, psz);
> +			/* Number of L1 pages to point to the L2 pages */
> +			npg = DIV_ROUND_UP(nl2 * SZ_8, psz);
> +		} else {
> +			npg = DIV_ROUND_UP(ITS_MAX_VPEID, epp);
> +			if (npg > GICR_VPROPBASER_PAGES_MAX) {
> +				pr_warn("GICR_VPROPBASER pages too large, reduce %llu->%u\n",
> +					npg, GICR_VPROPBASER_PAGES_MAX);
> +				npg = GICR_VPROPBASER_PAGES_MAX;
> +			}
> +		}
>  	} else {
>  		npg = 1;

Why don't you treat the two indirect cases at the same point? It
really should read:

	if (epp < ITS_MAX_VPEID && indirect) {
		[unchanged]
	} else {
		[compute the number of L1 pages in the !indirect case]
	}

>  	}
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index 728691365464..ace37dfbff20 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -303,6 +303,7 @@
>  #define GICR_VPROPBASER_4_1_Z		(1ULL << 52)
>  #define GICR_VPROPBASER_4_1_ADDR	GENMASK_ULL(51, 12)
>  #define GICR_VPROPBASER_4_1_SIZE	GENMASK_ULL(6, 0)
> +#define GICR_VPROPBASER_PAGES_MAX  128

Don't hardcode numbers. Use the definition of the SIZE field
instead. And if you must have a new #define, please use the 4_1
indication so that it isn't confused with the v4.0 layout.

I'd expect something like the following (untested) hack.

	M.

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 9a7a74239eab..555b86f375e1 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -2836,6 +2836,7 @@ static int allocate_vpe_l1_table(void)
 	unsigned int psz = SZ_64K;
 	unsigned int np, epp, esz;
 	struct page *page;
+	bool indirect;
 
 	if (!gic_rdists->has_rvpeid)
 		return 0;
@@ -2870,10 +2871,12 @@ static int allocate_vpe_l1_table(void)
 
 	/* First probe the page size */
 	val = FIELD_PREP(GICR_VPROPBASER_4_1_PAGE_SIZE, GIC_PAGE_SIZE_64K);
+	val |= GICR_VPROPBASER_4_1_INDIRECT;
 	gicr_write_vpropbaser(val, vlpi_base + GICR_VPROPBASER);
 	val = gicr_read_vpropbaser(vlpi_base + GICR_VPROPBASER);
 	gpsz = FIELD_GET(GICR_VPROPBASER_4_1_PAGE_SIZE, val);
 	esz = FIELD_GET(GICR_VPROPBASER_4_1_ENTRY_SIZE, val);
+	indirect = !!(val & GICR_VPROPBASER_4_1_INDIRECT);
 
 	switch (gpsz) {
 	default:
@@ -2906,7 +2909,7 @@ static int allocate_vpe_l1_table(void)
 	 * If we need more than just a single L1 page, flag the table
 	 * as indirect and compute the number of required L1 pages.
 	 */
-	if (epp < ITS_MAX_VPEID) {
+	if (epp < ITS_MAX_VPEID && indirect) {
 		int nl2;
 
 		val |= GICR_VPROPBASER_4_1_INDIRECT;
@@ -2917,7 +2920,8 @@ static int allocate_vpe_l1_table(void)
 		/* Number of L1 pages to point to the L2 pages */
 		npg = DIV_ROUND_UP(nl2 * SZ_8, psz);
 	} else {
-		npg = 1;
+		npg = DIV_ROUND_UP(ITS_MAX_VPEID, epp);
+		npg = clamp_val(npg, 1, (GICR_VPROPBASER_4_1_SIZE + 1));
 	}
 
 	val |= FIELD_PREP(GICR_VPROPBASER_4_1_SIZE, npg - 1);

-- 
Without deviation from the norm, progress is not possible.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

WARNING: multiple messages have this Message-ID (diff)
From: Marc Zyngier <maz@kernel.org>
To: Nianyao Tang <tangnianyao@huawei.com>
Cc: <tglx@linutronix.de>, <linux-kernel@vger.kernel.org>,
	<linux-arm-kernel@lists.infradead.org>, <guoyang2@huawei.com>,
	<wangwudi@hisilicon.com>
Subject: Re: [PATCH] irqchip/gic-v4.1:Check whether indirect table is supported in allocate_vpe_l1_table
Date: Mon, 22 Jan 2024 09:00:22 +0000	[thread overview]
Message-ID: <86sf2p91zt.wl-maz@kernel.org> (raw)
In-Reply-To: <20240122160607.1078960-1-tangnianyao@huawei.com>

[Fixing the LKML address, which has bits of Stephan's address embedded
in it...]

On Mon, 22 Jan 2024 16:06:07 +0000,
Nianyao Tang <tangnianyao@huawei.com> wrote:
> 
> In allocate_vpe_l1_table, when we fail to inherit VPE table from other
> redistributors or ITSs, and we allocate a new vpe table for current common 
> affinity field without checking whether indirect table is supported.
> Let's fix it.

Is there an actual implementation that doesn't support the indirect
property for the VPE table? I know this is allowed for consistency
with the original revision of the architecture, but I never expected
an actual GICv4.1 implementation to be *that* bad.

If that's the case, I'm a bit puzzled/worried.

> 
> Signed-off-by: Nianyao Tang <tangnianyao@huawei.com>
> ---
>  drivers/irqchip/irq-gic-v3-its.c   | 28 ++++++++++++++++++++++------
>  include/linux/irqchip/arm-gic-v3.h |  1 +
>  2 files changed, 23 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
> index d097001c1e3e..4146d1e285ec 100644
> --- a/drivers/irqchip/irq-gic-v3-its.c
> +++ b/drivers/irqchip/irq-gic-v3-its.c
> @@ -2836,6 +2836,7 @@ static int allocate_vpe_l1_table(void)
>  	unsigned int psz = SZ_64K;
>  	unsigned int np, epp, esz;
>  	struct page *page;
> +	bool indirect = false;

Why the upfront initialisation?

>  
>  	if (!gic_rdists->has_rvpeid)
>  		return 0;
> @@ -2890,6 +2891,12 @@ static int allocate_vpe_l1_table(void)
>  		break;
>  	}
>  
> +	/* probe the indirect */
> +	val = GICR_VPROPBASER_4_1_INDIRECT;
> +	gicr_write_vpropbaser(val, vlpi_base + GICR_VPROPBASER);
> +	val = gicr_read_vpropbaser(vlpi_base + GICR_VPROPBASER);
> +	indirect = !!(val & GICR_VPROPBASER_4_1_INDIRECT);

You can probe the indirect bit as part of the page-size probe, no need
for an extra R/W sequence.

> +
>  	/*
>  	 * Start populating the register from scratch, including RO fields
>  	 * (which we want to print in debug cases...)
> @@ -2907,15 +2914,24 @@ static int allocate_vpe_l1_table(void)
>  	 * as indirect and compute the number of required L1 pages.
>  	 */
>  	if (epp < ITS_MAX_VPEID) {
> -		int nl2;
> +		if (indirect) {
> +			int nl2;
>  
> -		val |= GICR_VPROPBASER_4_1_INDIRECT;
> +			val |= GICR_VPROPBASER_4_1_INDIRECT;
>  
> -		/* Number of L2 pages required to cover the VPEID space */
> -		nl2 = DIV_ROUND_UP(ITS_MAX_VPEID, epp);
> +			/* Number of L2 pages required to cover the VPEID space */
> +			nl2 = DIV_ROUND_UP(ITS_MAX_VPEID, epp);
>  
> -		/* Number of L1 pages to point to the L2 pages */
> -		npg = DIV_ROUND_UP(nl2 * SZ_8, psz);
> +			/* Number of L1 pages to point to the L2 pages */
> +			npg = DIV_ROUND_UP(nl2 * SZ_8, psz);
> +		} else {
> +			npg = DIV_ROUND_UP(ITS_MAX_VPEID, epp);
> +			if (npg > GICR_VPROPBASER_PAGES_MAX) {
> +				pr_warn("GICR_VPROPBASER pages too large, reduce %llu->%u\n",
> +					npg, GICR_VPROPBASER_PAGES_MAX);
> +				npg = GICR_VPROPBASER_PAGES_MAX;
> +			}
> +		}
>  	} else {
>  		npg = 1;

Why don't you treat the two indirect cases at the same point? It
really should read:

	if (epp < ITS_MAX_VPEID && indirect) {
		[unchanged]
	} else {
		[compute the number of L1 pages in the !indirect case]
	}

>  	}
> diff --git a/include/linux/irqchip/arm-gic-v3.h b/include/linux/irqchip/arm-gic-v3.h
> index 728691365464..ace37dfbff20 100644
> --- a/include/linux/irqchip/arm-gic-v3.h
> +++ b/include/linux/irqchip/arm-gic-v3.h
> @@ -303,6 +303,7 @@
>  #define GICR_VPROPBASER_4_1_Z		(1ULL << 52)
>  #define GICR_VPROPBASER_4_1_ADDR	GENMASK_ULL(51, 12)
>  #define GICR_VPROPBASER_4_1_SIZE	GENMASK_ULL(6, 0)
> +#define GICR_VPROPBASER_PAGES_MAX  128

Don't hardcode numbers. Use the definition of the SIZE field
instead. And if you must have a new #define, please use the 4_1
indication so that it isn't confused with the v4.0 layout.

I'd expect something like the following (untested) hack.

	M.

diff --git a/drivers/irqchip/irq-gic-v3-its.c b/drivers/irqchip/irq-gic-v3-its.c
index 9a7a74239eab..555b86f375e1 100644
--- a/drivers/irqchip/irq-gic-v3-its.c
+++ b/drivers/irqchip/irq-gic-v3-its.c
@@ -2836,6 +2836,7 @@ static int allocate_vpe_l1_table(void)
 	unsigned int psz = SZ_64K;
 	unsigned int np, epp, esz;
 	struct page *page;
+	bool indirect;
 
 	if (!gic_rdists->has_rvpeid)
 		return 0;
@@ -2870,10 +2871,12 @@ static int allocate_vpe_l1_table(void)
 
 	/* First probe the page size */
 	val = FIELD_PREP(GICR_VPROPBASER_4_1_PAGE_SIZE, GIC_PAGE_SIZE_64K);
+	val |= GICR_VPROPBASER_4_1_INDIRECT;
 	gicr_write_vpropbaser(val, vlpi_base + GICR_VPROPBASER);
 	val = gicr_read_vpropbaser(vlpi_base + GICR_VPROPBASER);
 	gpsz = FIELD_GET(GICR_VPROPBASER_4_1_PAGE_SIZE, val);
 	esz = FIELD_GET(GICR_VPROPBASER_4_1_ENTRY_SIZE, val);
+	indirect = !!(val & GICR_VPROPBASER_4_1_INDIRECT);
 
 	switch (gpsz) {
 	default:
@@ -2906,7 +2909,7 @@ static int allocate_vpe_l1_table(void)
 	 * If we need more than just a single L1 page, flag the table
 	 * as indirect and compute the number of required L1 pages.
 	 */
-	if (epp < ITS_MAX_VPEID) {
+	if (epp < ITS_MAX_VPEID && indirect) {
 		int nl2;
 
 		val |= GICR_VPROPBASER_4_1_INDIRECT;
@@ -2917,7 +2920,8 @@ static int allocate_vpe_l1_table(void)
 		/* Number of L1 pages to point to the L2 pages */
 		npg = DIV_ROUND_UP(nl2 * SZ_8, psz);
 	} else {
-		npg = 1;
+		npg = DIV_ROUND_UP(ITS_MAX_VPEID, epp);
+		npg = clamp_val(npg, 1, (GICR_VPROPBASER_4_1_SIZE + 1));
 	}
 
 	val |= FIELD_PREP(GICR_VPROPBASER_4_1_SIZE, npg - 1);

-- 
Without deviation from the norm, progress is not possible.

  reply	other threads:[~2024-01-22  9:01 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-01-22 16:06 [PATCH] irqchip/gic-v4.1:Check whether indirect table is supported in allocate_vpe_l1_table Nianyao Tang
2024-01-22  9:00 ` Marc Zyngier [this message]
2024-01-22  9:00   ` Marc Zyngier
2024-01-22 13:13   ` Tangnianyao
2024-01-22 13:13     ` Tangnianyao
2024-01-22 14:02     ` Marc Zyngier
2024-01-22 14:02       ` Marc Zyngier
2024-05-15  8:56       ` Tangnianyao
2024-05-15  8:56         ` Tangnianyao
2024-05-15  9:34         ` Marc Zyngier
2024-05-15  9:34           ` Marc Zyngier
2025-09-18  2:56           ` Tangnianyao
2025-09-18  9:50             ` Marc Zyngier
2025-09-18 14:19               ` Tangnianyao

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=86sf2p91zt.wl-maz@kernel.org \
    --to=maz@kernel.org \
    --cc=guoyang2@huawei.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=tangnianyao@huawei.com \
    --cc=tglx@linutronix.de \
    --cc=wangwudi@hisilicon.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.