Re: [PATCH v3 2/2] irqchip/loongson-eiointc: Add multiple interrupt pin routing support

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

 



Hi, Bibo,

Do you have some performance data? It is not worth making the driver
so complicated if there is no significant improvement.


Huacai

On Fri, Dec 13, 2024 at 11:50 AM Bibo Mao <maobibo@xxxxxxxxxxx> 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 knows interrupt pin information and reads specific
> EIOINTC_REG_ISR register. And there is only once EIOINTC_REG_ISR register
> access rather than four loop times, it  reduces VM-exit times.
>
> Signed-off-by: Bibo Mao <maobibo@xxxxxxxxxxx>
> ---
>  drivers/irqchip/irq-loongson-eiointc.c | 81 +++++++++++++++++++++++---
>  1 file changed, 74 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c
> index 72979f9f0e05..e504a5d3f0b1 100644
> --- a/drivers/irqchip/irq-loongson-eiointc.c
> +++ b/drivers/irqchip/irq-loongson-eiointc.c
> @@ -46,6 +46,7 @@
>  #define EIOINTC_ALL_ENABLE_VEC_MASK(vector)    (EIOINTC_ALL_ENABLE & ~BIT(vector & 0x1f))
>  #define EIOINTC_REG_ENABLE_VEC(vector)         (EIOINTC_REG_ENABLE + ((vector >> 5) << 2))
>  #define EIOINTC_USE_CPU_ENCODE                 BIT(0)
> +#define EIOINTC_ROUTE_MULT_IP                  BIT(1)
>
>  #define MAX_EIO_NODES          (NR_CPUS / CORES_PER_EIO_NODE)
>
> @@ -59,6 +60,13 @@
>  #define EIOINTC_REG_ROUTE_VEC_MASK(vector)     (0xff << EIOINTC_REG_ROUTE_VEC_SHIFT(vector))
>
>  static int nr_pics;
> +struct eiointc_priv;
> +typedef struct eiointc_ip_route {
> +       struct eiointc_priv     *priv;
> +       /* Offset Routed destination IP */
> +       int                     start;
> +       int                     end;
> +} eiointc_ip_route;
>
>  struct eiointc_priv {
>         u32                     node;
> @@ -69,6 +77,7 @@ struct eiointc_priv {
>         struct irq_domain       *eiointc_domain;
>         int                     flags;
>         irq_hw_number_t         parent_hwirq;
> +       eiointc_ip_route        route_info[VEC_REG_COUNT];
>  };
>
>  static struct eiointc_priv *eiointc_priv[MAX_IO_PICS];
> @@ -189,6 +198,7 @@ static int eiointc_router_init(unsigned int cpu)
>  {
>         int i, bit, cores, index, node;
>         unsigned int data;
> +       int hwirq, mask;
>
>         node = cpu_to_eio_node(cpu);
>         index = eiointc_index(node);
> @@ -198,6 +208,13 @@ static int eiointc_router_init(unsigned int cpu)
>                 return -EINVAL;
>         }
>
> +       /* Enable cpu interrupt pin from eiointc */
> +       hwirq = eiointc_priv[index]->parent_hwirq;
> +       mask = BIT(hwirq);
> +       if (eiointc_priv[index]->flags & EIOINTC_ROUTE_MULT_IP)
> +               mask |= BIT(hwirq + 1) | BIT(hwirq + 2) | BIT(hwirq + 3);
> +       set_csr_ecfg(mask);
> +
>         if (!(eiointc_priv[index]->flags & EIOINTC_USE_CPU_ENCODE))
>                 cores = CORES_PER_EIO_NODE;
>         else
> @@ -215,10 +232,28 @@ static int eiointc_router_init(unsigned int cpu)
>                         /*
>                          * Route to interrupt pin, relative offset used here
>                          * Offset 0 means routing to IP0 and so on
> -                        * Every 32 vector routing to one interrupt pin
> +                        *
> +                        * If flags is set with EIOINTC_ROUTE_MULT_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_MULT_IP) {
> +                               /* The first 64 vectors route to hwirq */
> +                               bit = BIT(hwirq++ - INT_HWI0);
> +                               data = bit | (bit << 8);
> +
> +                               /* The second 64 vectors route to hwirq + 1 */
> +                               bit = BIT(hwirq++ - INT_HWI0);
> +                               data |= (bit << 16) | (bit << 24);
> +
> +                               /*
> +                                * Route to hwirq + 2/hwirq + 3 separately
> +                                * in next loop
> +                                */
> +                       } else  {
> +                               bit = BIT(hwirq - INT_HWI0);
> +                               data = bit | (bit << 8) | (bit << 16) | (bit << 24);
> +                       }
>                         iocsr_write32(data, EIOINTC_REG_IPMAP + i * 4);
>                 }
>
> @@ -251,11 +286,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);
> +       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_MULT_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 */
> @@ -268,7 +310,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;
>                 }
> @@ -468,8 +510,33 @@ static int __init eiointc_init(struct eiointc_priv *priv, int parent_irq,
>         }
>
>         eiointc_priv[nr_pics++] = priv;
> +       /*
> +        * Only the first eiointc device on VM supports routing to
> +        * different Interrupt Pins. The later eiointc devices use
> +        * generic method if there are multiple eiointc devices in future
> +        */
> +       if (cpu_has_hypervisor && (nr_pics == 1)) {
> +               priv->flags |= EIOINTC_ROUTE_MULT_IP;
> +               priv->parent_hwirq = INT_HWI0;
> +       }
> +
> +       if (priv->flags & EIOINTC_ROUTE_MULT_IP) {
> +               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]);
> +               }
> +       } 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
>
>





[Index of Archives]     [LKML Archive]     [Linux ARM Kernel]     [Linux ARM]     [Git]     [Yosemite News]     [Linux SCSI]     [Linux Hams]

  Powered by Linux