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.
next prev parent 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.