Skip to content

Commit 9899b82

Browse files
bibo-maochenhuacai
authored andcommitted
irqchip/loongson-eiointc: Add virt extension support
Interrupts can be routed to maximal four virtual CPUs with real HW EIOINTC interrupt controller model, since interrupt routing is encoded with CPU bitmap and EIOINTC node combined method. Here add the EIOINTC virt extension support so that interrupts can be routed to 256 vCPUs in virtual machine mode. CPU bitmap is replaced with normal encoding and EIOINTC node type is removed, so there are 8 bits for cpu selection, at most 256 vCPUs are supported for interrupt routing. Reviewed-by: Thomas Gleixner <[email protected]> Co-developed-by: Song Gao <[email protected]> Signed-off-by: Song Gao <[email protected]> Signed-off-by: Bibo Mao <[email protected]> Signed-off-by: Huacai Chen <[email protected]>
1 parent 1928254 commit 9899b82

File tree

4 files changed

+207
-21
lines changed

4 files changed

+207
-21
lines changed

Documentation/arch/loongarch/irq-chip-model.rst

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,70 @@ to CPUINTC directly::
8585
| Devices |
8686
+---------+
8787

88+
Virtual Extended IRQ model
89+
==========================
90+
91+
In this model, IPI (Inter-Processor Interrupt) and CPU Local Timer interrupt
92+
go to CPUINTC directly, CPU UARTS interrupts go to PCH-PIC, while all other
93+
devices interrupts go to PCH-PIC/PCH-MSI and gathered by V-EIOINTC (Virtual
94+
Extended I/O Interrupt Controller), and then go to CPUINTC directly::
95+
96+
+-----+ +-------------------+ +-------+
97+
| IPI |--> | CPUINTC(0-255vcpu)| <-- | Timer |
98+
+-----+ +-------------------+ +-------+
99+
^
100+
|
101+
+-----------+
102+
| V-EIOINTC |
103+
+-----------+
104+
^ ^
105+
| |
106+
+---------+ +---------+
107+
| PCH-PIC | | PCH-MSI |
108+
+---------+ +---------+
109+
^ ^ ^
110+
| | |
111+
+--------+ +---------+ +---------+
112+
| UARTs | | Devices | | Devices |
113+
+--------+ +---------+ +---------+
114+
115+
116+
Description
117+
-----------
118+
V-EIOINTC (Virtual Extended I/O Interrupt Controller) is an extension of
119+
EIOINTC, it only works in VM mode which runs in KVM hypervisor. Interrupts can
120+
be routed to up to four vCPUs via standard EIOINTC, however with V-EIOINTC
121+
interrupts can be routed to up to 256 virtual cpus.
122+
123+
With standard EIOINTC, interrupt routing setting includes two parts: eight
124+
bits for CPU selection and four bits for CPU IP (Interrupt Pin) selection.
125+
For CPU selection there is four bits for EIOINTC node selection, four bits
126+
for EIOINTC CPU selection. Bitmap method is used for CPU selection and
127+
CPU IP selection, so interrupt can only route to CPU0 - CPU3 and IP0-IP3 in
128+
one EIOINTC node.
129+
130+
With V-EIOINTC it supports to route more CPUs and CPU IP (Interrupt Pin),
131+
there are two newly added registers with V-EIOINTC.
132+
133+
EXTIOI_VIRT_FEATURES
134+
--------------------
135+
This register is read-only register, which indicates supported features with
136+
V-EIOINTC. Feature EXTIOI_HAS_INT_ENCODE and EXTIOI_HAS_CPU_ENCODE is added.
137+
138+
Feature EXTIOI_HAS_INT_ENCODE is part of standard EIOINTC. If it is 1, it
139+
indicates that CPU Interrupt Pin selection can be normal method rather than
140+
bitmap method, so interrupt can be routed to IP0 - IP15.
141+
142+
Feature EXTIOI_HAS_CPU_ENCODE is entension of V-EIOINTC. If it is 1, it
143+
indicates that CPU selection can be normal method rather than bitmap method,
144+
so interrupt can be routed to CPU0 - CPU255.
145+
146+
EXTIOI_VIRT_CONFIG
147+
------------------
148+
This register is read-write register, for compatibility intterupt routed uses
149+
the default method which is the same with standard EIOINTC. If the bit is set
150+
with 1, it indicated HW to use normal method rather than bitmap method.
151+
88152
Advanced Extended IRQ model
89153
===========================
90154

Documentation/translations/zh_CN/arch/loongarch/irq-chip-model.rst

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,61 @@ PCH-LPC/PCH-MSI,然后被EIOINTC统一收集,再直接到达CPUINTC::
8787
| Devices |
8888
+---------+
8989

90+
虚拟扩展IRQ模型
91+
===============
92+
93+
在这种模型里面, IPI(Inter-Processor Interrupt) 和CPU本地时钟中断直接发送到CPUINTC,
94+
CPU串口 (UARTs) 中断发送到PCH-PIC, 而其他所有设备的中断则分别发送到所连接的PCH_PIC/
95+
PCH-MSI, 然后V-EIOINTC统一收集,再直接到达CPUINTC::
96+
97+
+-----+ +-------------------+ +-------+
98+
| IPI |--> | CPUINTC(0-255vcpu)| <-- | Timer |
99+
+-----+ +-------------------+ +-------+
100+
^
101+
|
102+
+-----------+
103+
| V-EIOINTC |
104+
+-----------+
105+
^ ^
106+
| |
107+
+---------+ +---------+
108+
| PCH-PIC | | PCH-MSI |
109+
+---------+ +---------+
110+
^ ^ ^
111+
| | |
112+
+--------+ +---------+ +---------+
113+
| UARTs | | Devices | | Devices |
114+
+--------+ +---------+ +---------+
115+
116+
V-EIOINTC 是EIOINTC的扩展, 仅工作在虚拟机模式下, 中断经EIOINTC最多可个路由到
117+
4个虚拟CPU. 但中断经V-EIOINTC最多可个路由到256个虚拟CPU.
118+
119+
传统的EIOINTC中断控制器,中断路由分为两个部分:8比特用于控制路由到哪个CPU,
120+
4比特用于控制路由到特定CPU的哪个中断管脚。控制CPU路由的8比特前4比特用于控制
121+
路由到哪个EIOINTC节点,后4比特用于控制此节点哪个CPU。中断路由在选择CPU路由
122+
和CPU中断管脚路由时,使用bitmap编码方式而不是正常编码方式,所以对于一个
123+
EIOINTC中断控制器节点,中断只能路由到CPU0 - CPU3,中断管脚IP0-IP3。
124+
125+
V-EIOINTC新增了两个寄存器,支持中断路由到更多CPU个和中断管脚。
126+
127+
V-EIOINTC功能寄存器
128+
-------------------
129+
功能寄存器是只读寄存器,用于显示V-EIOINTC支持的特性,目前两个支持两个特性
130+
EXTIOI_HAS_INT_ENCODE 和 EXTIOI_HAS_CPU_ENCODE。
131+
132+
特性EXTIOI_HAS_INT_ENCODE是传统EIOINTC中断控制器的一个特性,如果此比特为1,
133+
显示CPU中断管脚路由方式支持正常编码,而不是bitmap编码,所以中断可以路由到
134+
管脚IP0 - IP15。
135+
136+
特性EXTIOI_HAS_CPU_ENCODE是V-EIOINTC新增特性,如果此比特为1,表示CPU路由
137+
方式支持正常编码,而不是bitmap编码,所以中断可以路由到CPU0 - CPU255。
138+
139+
V-EIOINTC配置寄存器
140+
-------------------
141+
配置寄存器是可读写寄存器,为了兼容性考虑,如果不写此寄存器,中断路由采用
142+
和传统EIOINTC相同的路由设置。如果对应比特设置为1,表示采用正常路由方式而
143+
不是bitmap编码的路由方式。
144+
90145
高级扩展IRQ模型
91146
===============
92147

arch/loongarch/include/asm/irq.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ extern struct acpi_vector_group pch_group[MAX_IO_PICS];
6565
extern struct acpi_vector_group msi_group[MAX_IO_PICS];
6666

6767
#define CORES_PER_EIO_NODE 4
68+
#define CORES_PER_VEIO_NODE 256
6869

6970
#define LOONGSON_CPU_UART0_VEC 10 /* CPU UART0 */
7071
#define LOONGSON_CPU_THSENS_VEC 14 /* CPU Thsens */

drivers/irqchip/irq-loongson-eiointc.c

Lines changed: 87 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/irqdomain.h>
1515
#include <linux/irqchip/chained_irq.h>
1616
#include <linux/kernel.h>
17+
#include <linux/kvm_para.h>
1718
#include <linux/syscore_ops.h>
1819
#include <asm/numa.h>
1920

@@ -26,15 +27,37 @@
2627
#define EIOINTC_REG_ISR 0x1800
2728
#define EIOINTC_REG_ROUTE 0x1c00
2829

30+
#define EXTIOI_VIRT_FEATURES 0x40000000
31+
#define EXTIOI_HAS_VIRT_EXTENSION BIT(0)
32+
#define EXTIOI_HAS_ENABLE_OPTION BIT(1)
33+
#define EXTIOI_HAS_INT_ENCODE BIT(2)
34+
#define EXTIOI_HAS_CPU_ENCODE BIT(3)
35+
#define EXTIOI_VIRT_CONFIG 0x40000004
36+
#define EXTIOI_ENABLE BIT(1)
37+
#define EXTIOI_ENABLE_INT_ENCODE BIT(2)
38+
#define EXTIOI_ENABLE_CPU_ENCODE BIT(3)
39+
2940
#define VEC_REG_COUNT 4
3041
#define VEC_COUNT_PER_REG 64
3142
#define VEC_COUNT (VEC_REG_COUNT * VEC_COUNT_PER_REG)
3243
#define VEC_REG_IDX(irq_id) ((irq_id) / VEC_COUNT_PER_REG)
3344
#define VEC_REG_BIT(irq_id) ((irq_id) % VEC_COUNT_PER_REG)
3445
#define EIOINTC_ALL_ENABLE 0xffffffff
46+
#define EIOINTC_ALL_ENABLE_VEC_MASK(vector) (EIOINTC_ALL_ENABLE & ~BIT(vector & 0x1f))
47+
#define EIOINTC_REG_ENABLE_VEC(vector) (EIOINTC_REG_ENABLE + ((vector >> 5) << 2))
48+
#define EIOINTC_USE_CPU_ENCODE BIT(0)
3549

3650
#define MAX_EIO_NODES (NR_CPUS / CORES_PER_EIO_NODE)
3751

52+
/*
53+
* Routing registers are 32bit, and there is 8-bit route setting for every
54+
* interrupt vector. So one Route register contains four vectors routing
55+
* information.
56+
*/
57+
#define EIOINTC_REG_ROUTE_VEC(vector) (EIOINTC_REG_ROUTE + (vector & ~0x03))
58+
#define EIOINTC_REG_ROUTE_VEC_SHIFT(vector) ((vector & 0x03) << 3)
59+
#define EIOINTC_REG_ROUTE_VEC_MASK(vector) (0xff << EIOINTC_REG_ROUTE_VEC_SHIFT(vector))
60+
3861
static int nr_pics;
3962

4063
struct eiointc_priv {
@@ -44,6 +67,7 @@ struct eiointc_priv {
4467
cpumask_t cpuspan_map;
4568
struct fwnode_handle *domain_handle;
4669
struct irq_domain *eiointc_domain;
70+
int flags;
4771
};
4872

4973
static struct eiointc_priv *eiointc_priv[MAX_IO_PICS];
@@ -59,7 +83,10 @@ static void eiointc_enable(void)
5983

6084
static int cpu_to_eio_node(int cpu)
6185
{
62-
return cpu_logical_map(cpu) / CORES_PER_EIO_NODE;
86+
if (!kvm_para_has_feature(KVM_FEATURE_VIRT_EXTIOI))
87+
return cpu_logical_map(cpu) / CORES_PER_EIO_NODE;
88+
else
89+
return cpu_logical_map(cpu) / CORES_PER_VEIO_NODE;
6390
}
6491

6592
#ifdef CONFIG_SMP
@@ -89,6 +116,17 @@ static void eiointc_set_irq_route(int pos, unsigned int cpu, unsigned int mnode,
89116
}
90117
}
91118

119+
static void veiointc_set_irq_route(unsigned int vector, unsigned int cpu)
120+
{
121+
unsigned long reg = EIOINTC_REG_ROUTE_VEC(vector);
122+
unsigned int data;
123+
124+
data = iocsr_read32(reg);
125+
data &= ~EIOINTC_REG_ROUTE_VEC_MASK(vector);
126+
data |= cpu_logical_map(cpu) << EIOINTC_REG_ROUTE_VEC_SHIFT(vector);
127+
iocsr_write32(data, reg);
128+
}
129+
92130
static DEFINE_RAW_SPINLOCK(affinity_lock);
93131

94132
static int eiointc_set_irq_affinity(struct irq_data *d, const struct cpumask *affinity, bool force)
@@ -107,18 +145,24 @@ static int eiointc_set_irq_affinity(struct irq_data *d, const struct cpumask *af
107145
}
108146

109147
vector = d->hwirq;
110-
regaddr = EIOINTC_REG_ENABLE + ((vector >> 5) << 2);
111-
112-
/* Mask target vector */
113-
csr_any_send(regaddr, EIOINTC_ALL_ENABLE & (~BIT(vector & 0x1F)),
114-
0x0, priv->node * CORES_PER_EIO_NODE);
115-
116-
/* Set route for target vector */
117-
eiointc_set_irq_route(vector, cpu, priv->node, &priv->node_map);
118-
119-
/* Unmask target vector */
120-
csr_any_send(regaddr, EIOINTC_ALL_ENABLE,
121-
0x0, priv->node * CORES_PER_EIO_NODE);
148+
regaddr = EIOINTC_REG_ENABLE_VEC(vector);
149+
150+
if (priv->flags & EIOINTC_USE_CPU_ENCODE) {
151+
iocsr_write32(EIOINTC_ALL_ENABLE_VEC_MASK(vector), regaddr);
152+
veiointc_set_irq_route(vector, cpu);
153+
iocsr_write32(EIOINTC_ALL_ENABLE, regaddr);
154+
} else {
155+
/* Mask target vector */
156+
csr_any_send(regaddr, EIOINTC_ALL_ENABLE_VEC_MASK(vector),
157+
0x0, priv->node * CORES_PER_EIO_NODE);
158+
159+
/* Set route for target vector */
160+
eiointc_set_irq_route(vector, cpu, priv->node, &priv->node_map);
161+
162+
/* Unmask target vector */
163+
csr_any_send(regaddr, EIOINTC_ALL_ENABLE,
164+
0x0, priv->node * CORES_PER_EIO_NODE);
165+
}
122166

123167
irq_data_update_effective_affinity(d, cpumask_of(cpu));
124168

@@ -142,17 +186,23 @@ static int eiointc_index(int node)
142186

143187
static int eiointc_router_init(unsigned int cpu)
144188
{
145-
int i, bit;
146-
uint32_t data;
147-
uint32_t node = cpu_to_eio_node(cpu);
148-
int index = eiointc_index(node);
189+
int i, bit, cores, index, node;
190+
unsigned int data;
191+
192+
node = cpu_to_eio_node(cpu);
193+
index = eiointc_index(node);
149194

150195
if (index < 0) {
151196
pr_err("Error: invalid nodemap!\n");
152-
return -1;
197+
return -EINVAL;
153198
}
154199

155-
if ((cpu_logical_map(cpu) % CORES_PER_EIO_NODE) == 0) {
200+
if (!(eiointc_priv[index]->flags & EIOINTC_USE_CPU_ENCODE))
201+
cores = CORES_PER_EIO_NODE;
202+
else
203+
cores = CORES_PER_VEIO_NODE;
204+
205+
if ((cpu_logical_map(cpu) % cores) == 0) {
156206
eiointc_enable();
157207

158208
for (i = 0; i < eiointc_priv[0]->vec_count / 32; i++) {
@@ -168,7 +218,9 @@ static int eiointc_router_init(unsigned int cpu)
168218

169219
for (i = 0; i < eiointc_priv[0]->vec_count / 4; i++) {
170220
/* Route to Node-0 Core-0 */
171-
if (index == 0)
221+
if (eiointc_priv[index]->flags & EIOINTC_USE_CPU_ENCODE)
222+
bit = cpu_logical_map(0);
223+
else if (index == 0)
172224
bit = BIT(cpu_logical_map(0));
173225
else
174226
bit = (eiointc_priv[index]->node << 4) | 1;
@@ -375,7 +427,7 @@ static int __init acpi_cascade_irqdomain_init(void)
375427
static int __init eiointc_init(struct eiointc_priv *priv, int parent_irq,
376428
u64 node_map)
377429
{
378-
int i;
430+
int i, val;
379431

380432
node_map = node_map ? node_map : -1ULL;
381433
for_each_possible_cpu(i) {
@@ -395,6 +447,20 @@ static int __init eiointc_init(struct eiointc_priv *priv, int parent_irq,
395447
return -ENOMEM;
396448
}
397449

450+
if (kvm_para_has_feature(KVM_FEATURE_VIRT_EXTIOI)) {
451+
val = iocsr_read32(EXTIOI_VIRT_FEATURES);
452+
/*
453+
* With EXTIOI_ENABLE_CPU_ENCODE set
454+
* interrupts can route to 256 vCPUs.
455+
*/
456+
if (val & EXTIOI_HAS_CPU_ENCODE) {
457+
val = iocsr_read32(EXTIOI_VIRT_CONFIG);
458+
val |= EXTIOI_ENABLE_CPU_ENCODE;
459+
iocsr_write32(val, EXTIOI_VIRT_CONFIG);
460+
priv->flags = EIOINTC_USE_CPU_ENCODE;
461+
}
462+
}
463+
398464
eiointc_priv[nr_pics++] = priv;
399465
eiointc_router_init(0);
400466
irq_set_chained_handler_and_data(parent_irq, eiointc_irq_dispatch, priv);

0 commit comments

Comments
 (0)