lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <819bb7b2-cbbf-ea47-7bae-3a0902d48096@loongson.cn>
Date: Thu, 29 Aug 2024 09:15:28 +0800
From: maobibo <maobibo@...ngson.cn>
To: Huacai Chen <chenhuacai@...nel.org>
Cc: Jianmin Lv <lvjianmin@...ngson.cn>, WANG Xuerui <kernel@...0n.name>,
 Thomas Gleixner <tglx@...utronix.de>, loongarch@...ts.linux.dev,
 linux-kernel@...r.kernel.org, linux-mips@...r.kernel.org
Subject: Re: [RFC v2 2/2] irqchip/loongson-eiointc: Add multiple interrupt pin
 routing support



On 2024/8/28 下午9:56, Huacai Chen wrote:
> Hi, Bibo,
> 
> On Wed, Aug 28, 2024 at 3:06 PM Bibo Mao <maobibo@...ngson.cn> wrote:
>>
>> Eiointc interrupt controller support 256 interrupt vectors at most,
>> and irq handler gets interrupt status from base register group
>> EIOINTC_REG_ISR plus specific offset. It needs to read register group
>> EIOINTC_REG_ISR four times to get all 256 interrupt vectors status.
>>
>> Eiointc registers including EIOINTC_REG_ISR is software emulated for
>> VMs, there will be VM-exits when accessing eiointc registers. Here one
>> method is introduced so that eiointc interrupt controller can route
>> to different cpu interrupt pins for every 64 interrupt vectors. So
>> irq handler needs read only relative 64 interrupt vector, it  reduces
>> VM-exits.
>>
>> Signed-off-by: Bibo Mao <maobibo@...ngson.cn>
>> ---
>>   drivers/irqchip/irq-loongson-eiointc.c | 72 ++++++++++++++++++++++----
>>   1 file changed, 63 insertions(+), 9 deletions(-)
>>
>> diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c
>> index e9ec63d85ee8..c6bcb6625e6d 100644
>> --- a/drivers/irqchip/irq-loongson-eiointc.c
>> +++ b/drivers/irqchip/irq-loongson-eiointc.c
>> @@ -30,11 +30,20 @@
>>   #define VEC_REG_IDX(irq_id)    ((irq_id) / VEC_COUNT_PER_REG)
>>   #define VEC_REG_BIT(irq_id)     ((irq_id) % VEC_COUNT_PER_REG)
>>   #define EIOINTC_ALL_ENABLE     0xffffffff
>> +#define EIOINTC_ROUTE_MULTIPLE_IP      BIT(0)
>>
>>   #define MAX_EIO_NODES          (NR_CPUS / CORES_PER_EIO_NODE)
>>
>>   static int nr_pics;
>>
>> +struct eiointc_priv;
>> +struct eiointc_ip_route {
>> +       struct eiointc_priv     *priv;
>> +       /* Routed destination IP offset */
>> +       int                     start;
>> +       int                     end;
>> +};
>> +
>>   struct eiointc_priv {
>>          u32                     node;
>>          u32                     vec_count;
>> @@ -43,6 +52,8 @@ struct eiointc_priv {
>>          struct fwnode_handle    *domain_handle;
>>          struct irq_domain       *eiointc_domain;
>>          int                     parent_hwirq;
>> +       int                     flags;
>> +       struct eiointc_ip_route route_info[4];
>>   };
>>
>>   static struct eiointc_priv *eiointc_priv[MAX_IO_PICS];
>> @@ -145,12 +156,20 @@ static int eiointc_router_init(unsigned int cpu)
>>          uint32_t data;
>>          uint32_t node = cpu_to_eio_node(cpu);
>>          int index = eiointc_index(node);
>> +       int hwirq, mask;
>>
>>          if (index < 0) {
>>                  pr_err("Error: invalid nodemap!\n");
>>                  return -1;
>>          }
>>
>> +       /* Enable cpu interrupt pin routed from eiointc */
>> +       hwirq = eiointc_priv[index]->parent_hwirq;
>> +       mask = BIT(hwirq);
>> +       if (eiointc_priv[index]->flags & EIOINTC_ROUTE_MULTIPLE_IP)
>> +               mask |= BIT(hwirq + 1) | BIT(hwirq + 2) | BIT(hwirq + 3);
>> +       set_csr_ecfg(mask);
>> +
>>          if ((cpu_logical_map(cpu) % CORES_PER_EIO_NODE) == 0) {
>>                  eiointc_enable();
>>
>> @@ -161,12 +180,23 @@ static int eiointc_router_init(unsigned int cpu)
>>
>>                  for (i = 0; i < eiointc_priv[0]->vec_count / 32 / 4; i++) {
>>                          /*
>> -                        * Route to interrupt pin, using offset minus INT_HWI0
>> -                        * Offset 0 means IP0 and so on
>> -                        * Every 32 vector routing to one interrupt pin
>> +                        * Route to interrupt pin, minus INT_HWI0 as offset
>> +                        * Offset 0 means IP0 and so on, every 32 vector
>> +                        * routing to one interrupt pin
>> +                        *
>> +                        * If flags is set with EIOINTC_ROUTE_MULTIPLE_IP,
>> +                        * every 64 vector routes to different consecutive
>> +                        * IPs, otherwise all vector routes to the same IP
>>                           */
>> -                       bit = BIT(eiointc_priv[index]->parent_hwirq - INT_HWI0);
>> -                       data = bit | (bit << 8) | (bit << 16) | (bit << 24);
>> +                       if (eiointc_priv[index]->flags & EIOINTC_ROUTE_MULTIPLE_IP) {
>> +                               bit = BIT(hwirq++ - INT_HWI0);
>> +                               data = bit | (bit << 8);
>> +                               bit = BIT(hwirq++ - INT_HWI0);
>> +                               data |= (bit << 16) | (bit << 24);
>> +                       } else  {
>> +                               bit = BIT(hwirq - INT_HWI0);
>> +                               data = bit | (bit << 8) | (bit << 16) | (bit << 24);
>> +                       }
>>                          iocsr_write32(data, EIOINTC_REG_IPMAP + i * 4);
>>                  }
>>
>> @@ -197,11 +227,18 @@ static void eiointc_irq_dispatch(struct irq_desc *desc)
>>          u64 pending;
>>          bool handled = false;
>>          struct irq_chip *chip = irq_desc_get_chip(desc);
>> -       struct eiointc_priv *priv = irq_desc_get_handler_data(desc);
>> +       struct eiointc_ip_route *info = irq_desc_get_handler_data(desc);
>>
>>          chained_irq_enter(chip, desc);
>>
>> -       for (i = 0; i < eiointc_priv[0]->vec_count / VEC_COUNT_PER_REG; i++) {
>> +       /*
>> +        * If EIOINTC_ROUTE_MULTIPLE_IP is set, every 64 interrupt vectors in
>> +        * eiointc interrupt controller routes to different cpu interrupt pins
>> +        *
>> +        * Every cpu interrupt pin has its own irq handler, it is ok to
>> +        * read ISR for these 64 interrupt vectors rather than all vectors
>> +        */
>> +       for (i = info->start; i < info->end; i++) {
>>                  pending = iocsr_read64(EIOINTC_REG_ISR + (i << 3));
>>
>>                  /* Skip handling if pending bitmap is zero */
>> @@ -214,7 +251,7 @@ static void eiointc_irq_dispatch(struct irq_desc *desc)
>>                          int bit = __ffs(pending);
>>                          int irq = bit + VEC_COUNT_PER_REG * i;
>>
>> -                       generic_handle_domain_irq(priv->eiointc_domain, irq);
>> +                       generic_handle_domain_irq(info->priv->eiointc_domain, irq);
>>                          pending &= ~BIT(bit);
>>                          handled = true;
>>                  }
>> @@ -397,8 +434,25 @@ static int __init eiointc_init(struct eiointc_priv *priv, int parent_irq,
>>          }
>>
>>          eiointc_priv[nr_pics++] = priv;
>> +       if (cpu_has_hypervisor) {
>> +               priv->parent_hwirq = INT_HWI0;
>> +               for (i = 0; i < priv->vec_count / VEC_COUNT_PER_REG; i++) {
>> +                       priv->route_info[i].start  = priv->parent_hwirq - INT_HWI0 + i;
>> +                       priv->route_info[i].end    = priv->route_info[i].start + 1;
>> +                       priv->route_info[i].priv   = priv;
>> +                       parent_irq = get_percpu_irq(priv->parent_hwirq + i);
>> +                       irq_set_chained_handler_and_data(parent_irq, eiointc_irq_dispatch,
>> +                                                               &priv->route_info[i]);
>> +               }
>> +               priv->flags |= EIOINTC_ROUTE_MULTIPLE_IP;
> Can real machines also use EIOINTC_ROUTE_MULTIPLE_IP?
In theory it is possible on real machine also. Now there are potential 
problems which needs more code modification.

1. On real machine, liointc uses one or two IPs, 
EIOINTC_ROUTE_MULTIPLE_IP requires four IPs. eiointc uses bitmap IP map 
method now, only IP0-IP3 can be used.

2. For multiple eiointc support, instead IP0-IP3 can be used for 
multiple eiointc support since IPs is per-cpu.

On the other hand, what is the benefit doing such thing on real machine, 
we need cost about accessing iocsr register on real machine, there is 
such data from my side.

Regards
Bibo Mao
> 
> Huacai
> 
>> +       } else {
>> +               priv->route_info[0].start  = 0;
>> +               priv->route_info[0].end    = priv->vec_count / VEC_COUNT_PER_REG;
>> +               priv->route_info[0].priv   = priv;
>> +               irq_set_chained_handler_and_data(parent_irq, eiointc_irq_dispatch,
>> +                                                       &priv->route_info[0]);
>> +       }
>>          eiointc_router_init(0);
>> -       irq_set_chained_handler_and_data(parent_irq, eiointc_irq_dispatch, priv);
>>
>>          if (nr_pics == 1) {
>>                  register_syscore_ops(&eiointc_syscore_ops);
>> --
>> 2.39.3
>>


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ