[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 01/10] xen/arm: gicv3: refactor obtaining GIC addresses for common operations


  • To: Julien Grall <julien@xxxxxxx>, "xen-devel@xxxxxxxxxxxxxxxxxxxx" <xen-devel@xxxxxxxxxxxxxxxxxxxx>
  • From: Leonid Komarianskyi <Leonid_Komarianskyi@xxxxxxxx>
  • Date: Thu, 31 Jul 2025 13:19:07 +0000
  • Accept-language: en-US
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=epam.com; dmarc=pass action=none header.from=epam.com; dkim=pass header.d=epam.com; arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=1IdJXrIJRyYAqyNRyArEd1UdKvXGKXNT3fMCTvoK3G4=; b=PLYY9BcIpLCqSt3N/O3zNIYoT0E6V82dW3NwNBTggmLOHY1Nh/jKyHP6R4DSkpWKE3Oca//DsHlVAexXIAFvlOxAu72ogg09A4iwAxFj/7Aw6yxZSmtT/y3KKpU2XST6rdsvHSEb905oaw3sasNGlNG0a81NkL/m8cLqv2+o9hVRMuuoVtglSC0yWzrrF5c5RiCR5k0I4KO+HZUsBjyNnKdLigqu0TfL3vBWZzoQw6VzEFSiHcuvdwl9QAj+JWZyFS4SbB+AbWEBFVlvIX+PWymjz37Y5gItAviScT9HkoxAoWR+jcQkC0t7pPn9cUDYrGDbwGLSrhjW3rMcQwy3Pw==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=QIcwxqqsMqAt5l/M54KentVVcbGNQVdOfbFNSiOiyZL3vjLoTt66wp3TZUMGbej9Spegnm5V8UalsjJkyBekfK5N8S8x/opqeX0Px5Z9zhRIbIep/DU01REkgSOGzt7JVsqhlQtgVVNUi0VBxalvajtS6UMgePPgfRDRhdtCUOcVDeYyVvSFnlvADBiOBs/PDOdpHgbHNJTgJcZnatgs6/SqQkjtcqi7IRMkihSwQA4LDtFLCZnTcr/Co6ZDmGr1wrsG0yuNFraip3Uj+dLIuTD+B9Z4wwDQ4PPS7LMSp4xwC36MbKXznBVS0Xh2CYnGxLVa4YQac8w5pKnUJp9yvw==
  • Authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=epam.com;
  • Cc: Stefano Stabellini <sstabellini@xxxxxxxxxx>, Bertrand Marquis <bertrand.marquis@xxxxxxx>, Michal Orzel <michal.orzel@xxxxxxx>, Volodymyr Babchuk <Volodymyr_Babchuk@xxxxxxxx>
  • Delivery-date: Thu, 31 Jul 2025 13:19:23 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Thread-index: AQHb/KmxYbsxVZZCoU+xoPbKkuBEbLRJIUiAgAMgxgA=
  • Thread-topic: [PATCH 01/10] xen/arm: gicv3: refactor obtaining GIC addresses for common operations

Hello Julien,

Thank you for your close review and comments.

On 29.07.25 16:33, Julien Grall wrote:
> Hi Leonid,
> 
> On 24/07/2025 15:57, Leonid Komarianskyi wrote:
>> Currently, many common functions perform the same operations to calculate
>> GIC register addresses. This patch consolidates the similar code into
>> a separate helper function to improve maintainability and reduce 
>> duplication.
>> This refactoring also simplifies the implementation of eSPI support in 
>> future
>> changes.
>  > > Signed-off-by: Leonid Komarianskyi <leonid_komarianskyi@xxxxxxxx>
>> ---
>>   xen/arch/arm/gic-v3.c          | 99 ++++++++++++++++++++++------------
>>   xen/arch/arm/include/asm/irq.h |  1 +
>>   2 files changed, 67 insertions(+), 33 deletions(-)
>>
>> diff --git a/xen/arch/arm/gic-v3.c b/xen/arch/arm/gic-v3.c
>> index cd3e1acf79..8fd78aba44 100644
>> --- a/xen/arch/arm/gic-v3.c
>> +++ b/xen/arch/arm/gic-v3.c
>> @@ -445,17 +445,62 @@ static void gicv3_dump_state(const struct vcpu *v)
>>       }
>>   }
>> +static void __iomem *get_addr_by_offset(struct irq_desc *irqd, u32 
>> offset)
>> +{
>> +    switch ( irqd->irq )
>> +    {
>> +    case 0 ... (NR_GIC_LOCAL_IRQS - 1):
>> +        switch ( offset )
>> +        {
>> +        case GICD_ISENABLER:
>> +        case GICD_ICENABLER:
>> +        case GICD_ISPENDR:
>> +        case GICD_ICPENDR:
>> +        case GICD_ISACTIVER:
>> +        case GICD_ICACTIVER:
>> +            return (GICD_RDIST_SGI_BASE + offset);
>> +        case GICD_ICFGR:
>> +            return (GICD_RDIST_SGI_BASE + GICR_ICFGR1);
>> +        case GICD_IPRIORITYR:
>> +            return (GICD_RDIST_SGI_BASE + GICR_IPRIORITYR0 + irqd->irq);
>> +        default:
>> +            break;
>> +        }
>> +    case NR_GIC_LOCAL_IRQS ... SPI_MAX_INTID:
>> +        switch ( offset )
>> +        {
>> +        case GICD_ISENABLER:
>> +        case GICD_ICENABLER:
>> +        case GICD_ISPENDR:
>> +        case GICD_ICPENDR:
>> +        case GICD_ISACTIVER:
>> +        case GICD_ICACTIVER:
>> +            return (GICD + offset + (irqd->irq / 32) * 4);
>> +        case GICD_ICFGR:
>> +            return (GICD + GICD_ICFGR + (irqd->irq / 16) * 4);
>> +        case GICD_IROUTER:
>> +            return (GICD + GICD_IROUTER + irqd->irq * 8);
>> +        case GICD_IPRIORITYR:
>> +            return (GICD + GICD_IPRIORITYR + irqd->irq);
>> +        default:
>> +            break;
>> +        }
>> +    default:
>> +        break;
>> +    }
>> +
>> +    /* Something went wrong, we shouldn't be able to reach here */
>> +    panic("Invalid offset 0x%x for IRQ#%d", offset, irqd->irq);
> 
> This panic is worrying me because we have multiple switch above and it 
> is difficult to figure out whether everything was covered. ...

Initially, I was thinking about handling the errors more gently when 
dealing with invalid INTIDs or offsets. It looked like this:

     addr = get_addr_by_offset(desc, GICD_ICFGR);
     if ( !addr ) {
         pr_err("GICv3: cannot perform GIC operation invalid offset 0x%x 
for IRQ#%d\n", offset, irq);
         return;
     }

However, there is an issue with the gicv3_peek_irq function. Since it 
returns a bool, we cannot simply return either true or false from the 
function, as it will be interpreted as a valid value by the caller, even 
with an error message. For this reason, I decided to cover all valid 
INTIDs and offsets and trigger a panic only in an exceptionally rare 
case where we cannot obtain the correct address due to unexpected 
parameters.

Regarding your concerns about the panic:
After your comments, I rechecked the code and found that there is only 
one combination of INTID and offset where an invalid offset would 
trigger a panic compared with the mainline implementation:
gicv3_irq_set_affinity is invoked for INTIDs < NR_GIC_LOCAL_IRQS. 
Currently, in mainline implementation it does nothing in this particular 
case:

     if ( desc->irq >= NR_GIC_LOCAL_IRQS )
         writeq_relaxed_non_atomic(affinity, (GICD + GICD_IROUTER + 
desc->irq * 8));

This is not a valid situation because, according to the GICv3 
specification: GICD_IROUTER<n>, where n in range from 32 to 1019. 
Nevertheless, I will update the code to maintain the existing behavior 
unchanged without potential panic in this case.

Also, here are details, why panic will not be happened in real-life 
scenario:

The function is invoked from 5 places, and its behavior depends on two 
input parameters - the interrupt number and the offset. The main 
switch-case covers all valid INTIDs from 0 to 1019 (and will also cover 
the additional eSPI range from 4096 to 5119 with further changes). The 
current implementation prevents calling this function with different 
INTIDs, meaning that passing an invalid INTID represents a truly 
critical issue that could potentially result only from
improper code changes or unpredictable errors (e.g., memory corruption).
Moreover, compared to the current mainline implementation, passing an 
invalid IRQ would silently write to an unknown address, which is at 
least harder to debug. On the other hand, triggering a panic makes it 
much easier to identify, debug, and resolve this potential issue.

The second part is nested switch-case that handles all of possible 
defined values that can be passed to the function such as:
GICD_ISENABLER, GICD_ICENABLER, GICD_ISPENDR, GICD_ICPENDR, 
GICD_ISACTIVER, GICD_ICACTIVER, GICD_ICFGR, GICD_IROUTER and 
GICD_IPRIORITYR.
Even with the current mainline implementation, there are no ways to 
invoke e.g. gicv3_poke/peek_irq, gicv3_set_irq_type, 
gicv3_set_irq_priority or gicv3_irq_set_affinity with some differ offset 
values as mentioned previously.

To summarize, a panic would occur only in two cases: improper future 
code modifications or unpredictable errors (e.g., memory corruption).
In my opinion, it would require a major issue to trigger the panic.

What do you think? Is it acceptable to leave the panic here after the 
clarifications described above, or would it be better to handle it in a 
different way?


> ... Therefore if you want to consolidate some code, then I would prefer if 
> we introduce an helper just to deal with that logic. The rest (i.e. 
> ICFGR, IROUTER, IPRIORITY) should stay inlined.

The changes in this patch not only refactor existing logic but also 
simplify the implementation of eSPI handling in the third patch of this 
series:
https://patchew.org/Xen/cover.1753367178.git.leonid._5Fkomarianskyi@xxxxxxxx/790b1d3876206c8236986d7237173dacae99cac2.1753367178.git.leonid._5Fkomarianskyi@xxxxxxxx/

If this function were to handle only some of the required GIC registers, 
it would necessitate many additional #ifdefs and if conditions in the 
remaining functions. For example, if get_addr_by_offset did not handle 
GICD_IROUTER, GICD_ICFGR, and GICD_IPRIORITYR offsets, adding 
eSPI-related code would look like this:

gicv3_set_irq_type:
...
     if ( irq >= NR_GIC_LOCAL_IRQS)
         base = GICD + GICD_ICFGR + (irq / 16) * 4;
     else
         base = GICD_RDIST_SGI_BASE + GICR_ICFGR1;
#ifdef CONFIG_GICV3_ESPI
     if (is_espi(irq))
         base = (GICD + GICD_ICFGRnE + (ESPI_INTID2IDX(irq) / 16) * 4);
#endif

gicv3_irq_set_affinity:
...
#ifdef CONFIG_GICV3_ESPI
     if (is_espi(desc->irq))
         writeq_relaxed_non_atomic(affinity, (GICD + GICD_IROUTERnE + 
ESPI_INTID2IDX(desc->irq) * 8));
     else
#endif
     if ( desc->irq >= NR_GIC_LOCAL_IRQS )
         writeq_relaxed_non_atomic(affinity, (GICD + GICD_IROUTER + 
desc->irq * 8));

gicv3_set_irq_priority:
...
     /* Set priority */
     if ( irq < NR_GIC_LOCAL_IRQS )
         writeb_relaxed(priority, GICD_RDIST_SGI_BASE + GICR_IPRIORITYR0 
+ irq);
     else
#ifdef CONFIG_GICV3_ESPI
     if (is_espi(irq))
         writeb_relaxed(priority, GICD + GICD_IPRIORITYRnE + 
ESPI_INTID2IDX(irq));
     else
#endif
         writeb_relaxed(priority, GICD + GICD_IPRIORITYR + irq);


This code seems less readable, so I opted to refactor all relevant 
locations and prepare a single function that can be easily modified and 
maintained. By the way, I was inspired by a Linux kernel patch that was 
introduced in the same series as the eSPI support implementation for 
Linux. That patch refactored the code prior to implementing eSPI:
https://github.com/torvalds/linux/commit/e91b036e1c20d80419164ddfc32125052df3fb39
So I decided to make the changes in a similar way - on the first step, 
refactoring the existing functionality to make implementing eSPI support 
smoother. And then introduce the eSPI implementation.

I would really like to hear your thoughts after my comments, on whether 
keeping the current handling of the entire register group makes sense, 
or not.

Cheers,
Leonid

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.