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]

 





On 2024/12/31 下午9:07, Huacai Chen wrote:
Hi, Bibo,

Do you have some performance data? It is not worth making the driver
so complicated if there is no significant improvement.
There will be 6-8% improvement with netperf UDP_RR option on 10G etherther device in internal test.

Will publish the performance data when irqchip in kernel is merged in qemu side, so others can reproduce it.

Regards
Bibo Mao


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