* [PATCH v4 0/2] irqchip/loongson-eiointc: Add multiple interrupt pin routing support
@ 2025-08-04 8:19 Bibo Mao
2025-08-04 8:19 ` [PATCH v4 1/2] irqchip/loongson-eiointc: Route interrupt parsed from bios table Bibo Mao
2025-08-04 8:19 ` [PATCH v4 2/2] irqchip/loongson-eiointc: Add multiple interrupt pin routing support Bibo Mao
0 siblings, 2 replies; 3+ messages in thread
From: Bibo Mao @ 2025-08-04 8:19 UTC (permalink / raw)
To: Huacai Chen, Jianmin Lv
Cc: WANG Xuerui, Thomas Gleixner, loongarch, linux-kernel, linux-mips
There are four times EIOINTC_REG_ISR register group access in eiointc irq
handler, in order to get all irq status about 256 interrupt vectors. It
causes four times VM-exits since eiointc register are software emulated,
here multiple interrupt pin routing is introduced and each 64 interrupt
vector is routed to one interrupt pin.
With this method, there will be only once EIOINTC_REG_ISR register
group acces in irq handler, it reduces VM-exits.
There is about 6% improvement with netperf -t UDP_RR on 3C5000 Dual-way
machine, where netserver runs in VM and netperf runs in host.
Socket Size Request Resp. Elapsed Trans Improve
Send Recv Size Size Time Rate
bytes Bytes bytes bytes secs. per sec
Orininal 212992 212992 1 1 10.00 21689.78
With Patch 212992 212992 1 1 10.00 23022.67 +6%
---
v3 ... v4:
1. Update to kernel 6.16
2. Add performance result
v2 ... v3:
1. Update to latest kernel version and solve some confliction.
2. Add strict check about multiple interrupt pin support, only the first
eiointc device support this since intterrupt pin is limited. In order
to support multiple eiointc driver in future if there is in future.
v1 ... v2:
1. Add different route_info handler as eiointc interrupt handler
parameter, so that irq handler can read corresponding ISR
2. Call function set_csr_ecfg() to enable cpu interrupt pin in eiointc
driver inside.
---
Bibo Mao (2):
irqchip/loongson-eiointc: Route interrupt parsed from bios table
irqchip/loongson-eiointc: Add multiple interrupt pin routing support
drivers/irqchip/irq-loongson-eiointc.c | 96 +++++++++++++++++++++++---
1 file changed, 88 insertions(+), 8 deletions(-)
base-commit: 3c4a063b1f8ab71352df1421d9668521acb63cd9
--
2.39.3
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH v4 1/2] irqchip/loongson-eiointc: Route interrupt parsed from bios table
2025-08-04 8:19 [PATCH v4 0/2] irqchip/loongson-eiointc: Add multiple interrupt pin routing support Bibo Mao
@ 2025-08-04 8:19 ` Bibo Mao
2025-08-04 8:19 ` [PATCH v4 2/2] irqchip/loongson-eiointc: Add multiple interrupt pin routing support Bibo Mao
1 sibling, 0 replies; 3+ messages in thread
From: Bibo Mao @ 2025-08-04 8:19 UTC (permalink / raw)
To: Huacai Chen, Jianmin Lv
Cc: WANG Xuerui, Thomas Gleixner, loongarch, linux-kernel, linux-mips
Interrupt controller eiointc routes irq to cpu interface IP0 - IP7,
now it is hard-coded that eiointc routes irq to CPU started from IP1,
however with function irq_create_mapping() parameter parent hwirq
uses irq parsed from ACPI or DTS table.
Routed interrupt pin need be the consistent with parent hwirq.
Signed-off-by: Bibo Mao <maobibo@loongson.cn>
---
drivers/irqchip/irq-loongson-eiointc.c | 19 ++++++++++++++++---
1 file changed, 16 insertions(+), 3 deletions(-)
diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c
index b2860eb2d32c..3e987d1232d2 100644
--- a/drivers/irqchip/irq-loongson-eiointc.c
+++ b/drivers/irqchip/irq-loongson-eiointc.c
@@ -68,6 +68,7 @@ struct eiointc_priv {
struct fwnode_handle *domain_handle;
struct irq_domain *eiointc_domain;
int flags;
+ irq_hw_number_t parent_hwirq;
};
static struct eiointc_priv *eiointc_priv[MAX_IO_PICS];
@@ -211,7 +212,12 @@ static int eiointc_router_init(unsigned int cpu)
}
for (i = 0; i < eiointc_priv[0]->vec_count / 32 / 4; i++) {
- bit = BIT(1 + index); /* Route to IP[1 + index] */
+ /*
+ * 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
+ */
+ bit = BIT(eiointc_priv[index]->parent_hwirq - INT_HWI0);
data = bit | (bit << 8) | (bit << 16) | (bit << 24);
iocsr_write32(data, EIOINTC_REG_IPMAP + i * 4);
}
@@ -495,7 +501,7 @@ int __init eiointc_acpi_init(struct irq_domain *parent,
priv->vec_count = VEC_COUNT;
priv->node = acpi_eiointc->node;
-
+ priv->parent_hwirq = acpi_eiointc->cascade;
parent_irq = irq_create_mapping(parent, acpi_eiointc->cascade);
ret = eiointc_init(priv, parent_irq, acpi_eiointc->node_map);
@@ -529,6 +535,7 @@ static int __init eiointc_of_init(struct device_node *of_node,
{
int parent_irq, ret;
struct eiointc_priv *priv;
+ struct irq_data *irq_data;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv)
@@ -544,6 +551,12 @@ static int __init eiointc_of_init(struct device_node *of_node,
if (ret < 0)
goto out_free_priv;
+ irq_data = irq_get_irq_data(parent_irq);
+ if (!irq_data) {
+ ret = -ENODEV;
+ goto out_free_priv;
+ }
+
/*
* In particular, the number of devices supported by the LS2K0500
* extended I/O interrupt vector is 128.
@@ -552,7 +565,7 @@ static int __init eiointc_of_init(struct device_node *of_node,
priv->vec_count = 128;
else
priv->vec_count = VEC_COUNT;
-
+ priv->parent_hwirq = irqd_to_hwirq(irq_data);
priv->node = 0;
priv->domain_handle = of_fwnode_handle(of_node);
--
2.39.3
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH v4 2/2] irqchip/loongson-eiointc: Add multiple interrupt pin routing support
2025-08-04 8:19 [PATCH v4 0/2] irqchip/loongson-eiointc: Add multiple interrupt pin routing support Bibo Mao
2025-08-04 8:19 ` [PATCH v4 1/2] irqchip/loongson-eiointc: Route interrupt parsed from bios table Bibo Mao
@ 2025-08-04 8:19 ` Bibo Mao
1 sibling, 0 replies; 3+ messages in thread
From: Bibo Mao @ 2025-08-04 8:19 UTC (permalink / raw)
To: Huacai Chen, Jianmin Lv
Cc: WANG Xuerui, Thomas Gleixner, loongarch, linux-kernel, linux-mips
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@loongson.cn>
---
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 3e987d1232d2..081787ecdcdd 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;
+struct eiointc_ip_route {
+ struct eiointc_priv *priv;
+ /* Offset Routed destination IP */
+ int start;
+ int end;
+};
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;
+ struct 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);
+ 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_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
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2025-08-04 8:19 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-04 8:19 [PATCH v4 0/2] irqchip/loongson-eiointc: Add multiple interrupt pin routing support Bibo Mao
2025-08-04 8:19 ` [PATCH v4 1/2] irqchip/loongson-eiointc: Route interrupt parsed from bios table Bibo Mao
2025-08-04 8:19 ` [PATCH v4 2/2] irqchip/loongson-eiointc: Add multiple interrupt pin routing support Bibo Mao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).