Re: [RFC v2 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,

On Wed, Aug 28, 2024 at 3:06 PM 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 needs read only relative 64 interrupt vector, it  reduces
> VM-exits.
>
> Signed-off-by: Bibo Mao <maobibo@xxxxxxxxxxx>
> ---
>  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?

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
>





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

  Powered by Linux