lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAAhV-H4KcovRtPqXQfn0TJ1gpM6Hs5=D0Q3KmYi_YYC0BATfEA@mail.gmail.com>
Date: Tue, 25 Jun 2024 22:19:35 +0800
From: Huacai Chen <chenhuacai@...nel.org>
To: Song Gao <gaosong@...ngson.cn>
Cc: linux-kernel@...r.kernel.org, jiaxun.yang@...goat.com, tglx@...utronix.de, 
	maobibo@...ngson.cn
Subject: Re: [PATCH v3] irqchip/loongson-eiointc: Add extioi virt extension support

Hi, Song,

On Mon, Jun 24, 2024 at 5:01 PM Song Gao <gaosong@...ngson.cn> wrote:
>
> Interrupts can be routed to maximal four virtual CPUs with one external
> hardware interrupt. Add the extioi virt extension support so that
> Interrupts can be routed to 256 vcpus on hypervior mode.
>
> Signed-off-by: Song Gao <gaosong@...ngson.cn>
> ---
> v3:
> - Introduce V-EIOINTC and update the Chinese document.
> - Link to v2: https://lore.kernel.org/all/20240611123348.8374-1-gaosong@loongson.cn/
>
> v2:
> - Simplify commit messages and code.
> - Follow the documented tip tree coding style.
> - Add the virtual extended interrupt model to the documentation.
> - Link to v1: https://lore.kernel.org/all/20240605070229.2569875-1-gaosong@loongson.cn/
>
>  .../arch/loongarch/irq-chip-model.rst         |  32 ++++++
>  .../zh_CN/arch/loongarch/irq-chip-model.rst   |  29 +++++
>  arch/loongarch/include/asm/irq.h              |   1 +
>  drivers/irqchip/irq-loongson-eiointc.c        | 104 ++++++++++++++----
>  4 files changed, 146 insertions(+), 20 deletions(-)
>
> diff --git a/Documentation/arch/loongarch/irq-chip-model.rst b/Documentation/arch/loongarch/irq-chip-model.rst
> index 7988f4192363..36435f29e451 100644
> --- a/Documentation/arch/loongarch/irq-chip-model.rst
> +++ b/Documentation/arch/loongarch/irq-chip-model.rst
> @@ -85,6 +85,38 @@ to CPUINTC directly::
>      | Devices |
>      +---------+
>
> +Virtual extended IRQ model
> +==========================
> +
> +In this model, IPI (Inter-Processor Interrupt) and CPU Local Timer interrupt
> +go to CPUINTC directly, CPU UARTS interrupts go to PCH-PIC, while all other
> +devices interrupts go to PCH-PIC/PCH-MSI and gathered by V-EIOINTC (Virtual
> +Extended I/O Interrupt Controller), and then go to CPUINTC directly::
> +
> +       +-----+    +-------------------+     +-------+
> +       | IPI |--> | CPUINTC(0-255vcpu)| <-- | Timer |
> +       +-----+    +-------------------+     +-------+
> +                            ^
> +                            |
> +                      +-----------+
> +                      | V-EIOINTC |
> +                      +-----------+
> +                       ^         ^
> +                       |         |
> +                +---------+ +---------+
> +                | PCH-PIC | | PCH-MSI |
> +                +---------+ +---------+
> +                  ^      ^          ^
> +                  |      |          |
> +           +--------+ +---------+ +---------+
> +           | UARTs  | | Devices | | Devices |
> +           +--------+ +---------+ +---------+
> +
> +
> +V-EIOINTC (Virtual Extended I/O Interrupt Controller) is an extension of EIOINTC,
> +it only works in hypervior mode. Interrupts can be routed to up to four virtual
> +cpus via EIOINTC, but interrupts can be routed to up to 256 virtual cpus via V-EIOINTC.

If possible, it is a little better to introduce EXTIOI_VIRT_FEATURES
and EXTIOI_VIRT_CONFIG here.

> +
>  ACPI-related definitions
>  ========================
>
> diff --git a/Documentation/translations/zh_CN/arch/loongarch/irq-chip-model.rst b/Documentation/translations/zh_CN/arch/loongarch/irq-chip-model.rst
> index f1e9ab18206c..f211ed192bfc 100644
> --- a/Documentation/translations/zh_CN/arch/loongarch/irq-chip-model.rst
> +++ b/Documentation/translations/zh_CN/arch/loongarch/irq-chip-model.rst
> @@ -87,6 +87,35 @@ PCH-LPC/PCH-MSI,然后被EIOINTC统一收集,再直接到达CPUINTC::
>      | Devices |
>      +---------+
>
> +虚拟扩展IRQ模型
> +===============
> +
> +在这种模型里面, IPI(Inter-Processor Interrupt) 和CPU本地时钟中断直接发送到CPUINTC,
> +CPU串口 (UARTs) 中断发送到PCH-PIC, 而其他所有设备的中断则分别发送到所连接的PCH_PIC/
> +PCH-MSI, 然后V-EIOINTC统一收集,再直接到达CPUINTC::
> +
> +        +-----+    +-------------------+     +-------+
> +        | IPI |--> | CPUINTC(0-255vcpu)| <-- | Timer |
> +        +-----+    +-------------------+     +-------+
> +                             ^
> +                             |
> +                       +-----------+
> +                       | V-EIOINTC |
> +                       +-----------+
> +                        ^         ^
> +                        |         |
> +                 +---------+ +---------+
> +                 | PCH-PIC | | PCH-MSI |
> +                 +---------+ +---------+
> +                   ^      ^          ^
> +                   |      |          |
> +            +--------+ +---------+ +---------+
> +            | UARTs  | | Devices | | Devices |
> +            +--------+ +---------+ +---------+
> +
> +V-EIOINTC 是EIOINTC的扩展, 仅工作在hyperisor模式下, 中断经EIOINTC最多可个路由到4个
> +虚拟cpu. 但中断经V-EIOINTC最多可个路由到256个虚拟cpu.
> +
>  ACPI相关的定义
>  ==============
>
> diff --git a/arch/loongarch/include/asm/irq.h b/arch/loongarch/include/asm/irq.h
> index 480418bc5071..c97a7ab0e56f 100644
> --- a/arch/loongarch/include/asm/irq.h
> +++ b/arch/loongarch/include/asm/irq.h
> @@ -53,6 +53,7 @@ struct acpi_vector_group {
>  extern struct acpi_vector_group pch_group[MAX_IO_PICS];
>  extern struct acpi_vector_group msi_group[MAX_IO_PICS];
>
> +#define MAX_CORES_PER_EIO_NODE 256
Rename it to CORES_PER_VEIO_NODE and put it after CORES_PER_EIO_NODE is better.

>  #define CORES_PER_EIO_NODE     4
>
>  #define LOONGSON_CPU_UART0_VEC         10 /* CPU UART0 */
> diff --git a/drivers/irqchip/irq-loongson-eiointc.c b/drivers/irqchip/irq-loongson-eiointc.c
> index c7ddebf312ad..430fda9e8ce5 100644
> --- a/drivers/irqchip/irq-loongson-eiointc.c
> +++ b/drivers/irqchip/irq-loongson-eiointc.c
> @@ -23,15 +23,43 @@
>  #define EIOINTC_REG_ISR                0x1800
>  #define EIOINTC_REG_ROUTE      0x1c00
>
> +#define EXTIOI_VIRT_FEATURES           0x40000000
> +#define  EXTIOI_HAS_VIRT_EXTENSION     BIT(0)
> +#define  EXTIOI_HAS_ENABLE_OPTION      BIT(1)
> +#define  EXTIOI_HAS_INT_ENCODE         BIT(2)
> +#define  EXTIOI_HAS_CPU_ENCODE         BIT(3)
> +#define EXTIOI_VIRT_CONFIG             0x40000004
> +#define  EXTIOI_ENABLE                 BIT(1)
> +#define  EXTIOI_ENABLE_INT_ENCODE      BIT(2)
> +#define  EXTIOI_ENABLE_CPU_ENCODE      BIT(3)
> +
>  #define VEC_REG_COUNT          4
>  #define VEC_COUNT_PER_REG      64
>  #define VEC_COUNT              (VEC_REG_COUNT * VEC_COUNT_PER_REG)
>  #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_ALL_ENABLE_VEC_MASK(vector)    \
> +       (EIOINTC_ALL_ENABLE & ~BIT(vector & 0x1F))
> +#define EIOINTC_REG_ENABLE_VEC(vector)         \
> +       (EIOINTC_REG_ENABLE + ((vector >> 5) << 2))
>
>  #define MAX_EIO_NODES          (NR_CPUS / CORES_PER_EIO_NODE)
>
> +/*
> + * Routing registers contain four vectors and have an offset of four to
> + * the base. The routing information is 8 bit wide.
> + */
> +
> +#define EIOINTC_REG_ROUTE_VEC(vector)          \
> +       (EIOINTC_REG_ROUTE + (vector & ~0x03))
> +
> +#define EIOINTC_REG_ROUTE_VEC_SHIFT(vector)    \
> +       ((vector & 0x03) << 3)
> +
> +#define EIOINTC_REG_ROUTE_VEC_MASK(vector)     \
> +       (0xff << EIOINTC_REG_ROUTE_VEC_SHIFT(vector))
Line break is unnecessary for these macros.

> +
>  static int nr_pics;
>
>  struct eiointc_priv {
> @@ -41,6 +69,7 @@ struct eiointc_priv {
>         cpumask_t               cpuspan_map;
>         struct fwnode_handle    *domain_handle;
>         struct irq_domain       *eiointc_domain;
> +       bool                    cpu_encoded;
>  };
>
>  static struct eiointc_priv *eiointc_priv[MAX_IO_PICS];
> @@ -56,7 +85,9 @@ static void eiointc_enable(void)
>
>  static int cpu_to_eio_node(int cpu)
>  {
> -       return cpu_logical_map(cpu) / CORES_PER_EIO_NODE;
> +       int cores = cpu_has_hypervisor ? MAX_CORES_PER_EIO_NODE : CORES_PER_EIO_NODE;
I think the correct condition is not cpu_has_hypervisor, but something
read from the virtual registers?

Huacai
> +
> +       return cpu_logical_map(cpu) / cores;
>  }
>
>  #ifdef CONFIG_SMP
> @@ -88,6 +119,16 @@ static void eiointc_set_irq_route(int pos, unsigned int cpu, unsigned int mnode,
>
>  static DEFINE_RAW_SPINLOCK(affinity_lock);
>
> +static void virt_extioi_set_irq_route(unsigned int vector, unsigned int cpu)
> +{
> +       unsigned long reg = EIOINTC_REG_ROUTE_VEC(vector);
> +       u32 data = iocsr_read32(reg);
> +
> +       data &= ~EIOINTC_REG_ROUTE_VEC_MASK(vector);
> +       data |= cpu_logical_map(cpu) << EIOINTC_REG_ROUTE_VEC_SHIFT(vector);
> +       iocsr_write32(data, reg);
> +}
> +
>  static int eiointc_set_irq_affinity(struct irq_data *d, const struct cpumask *affinity, bool force)
>  {
>         unsigned int cpu;
> @@ -104,18 +145,24 @@ static int eiointc_set_irq_affinity(struct irq_data *d, const struct cpumask *af
>         }
>
>         vector = d->hwirq;
> -       regaddr = EIOINTC_REG_ENABLE + ((vector >> 5) << 2);
> -
> -       /* Mask target vector */
> -       csr_any_send(regaddr, EIOINTC_ALL_ENABLE & (~BIT(vector & 0x1F)),
> -                       0x0, priv->node * CORES_PER_EIO_NODE);
> -
> -       /* Set route for target vector */
> -       eiointc_set_irq_route(vector, cpu, priv->node, &priv->node_map);
> -
> -       /* Unmask target vector */
> -       csr_any_send(regaddr, EIOINTC_ALL_ENABLE,
> -                       0x0, priv->node * CORES_PER_EIO_NODE);
> +       regaddr = EIOINTC_REG_ENABLE_VEC(vector);
> +
> +       if (priv->cpu_encoded) {
> +               iocsr_write32(EIOINTC_ALL_ENABLE_VEC_MASK(vector), regaddr);
> +               virt_extioi_set_irq_route(vector, cpu);
> +               iocsr_write32(EIOINTC_ALL_ENABLE, regaddr);
> +       } else {
> +               /* Mask target vector */
> +               csr_any_send(regaddr, EIOINTC_ALL_ENABLE_VEC_MASK(vector),
> +                            0x0, priv->node * CORES_PER_EIO_NODE);
> +
> +               /* Set route for target vector */
> +               eiointc_set_irq_route(vector, cpu, priv->node, &priv->node_map);
> +
> +               /* Unmask target vector */
> +               csr_any_send(regaddr, EIOINTC_ALL_ENABLE,
> +                            0x0, priv->node * CORES_PER_EIO_NODE);
> +       }
>
>         irq_data_update_effective_affinity(d, cpumask_of(cpu));
>
> @@ -139,17 +186,20 @@ static int eiointc_index(int node)
>
>  static int eiointc_router_init(unsigned int cpu)
>  {
> -       int i, bit;
> -       uint32_t data;
> -       uint32_t node = cpu_to_eio_node(cpu);
> -       int index = eiointc_index(node);
> +       uint32_t data, node;
> +       int i, bit, cores, index;
> +
> +       node = cpu_to_eio_node(cpu);
> +       index = eiointc_index(node);
>
>         if (index < 0) {
>                 pr_err("Error: invalid nodemap!\n");
> -               return -1;
> +               return -EINVAL;
>         }
>
> -       if ((cpu_logical_map(cpu) % CORES_PER_EIO_NODE) == 0) {
> +       cores = (cpu_has_hypervisor ? MAX_CORES_PER_EIO_NODE : CORES_PER_EIO_NODE);
> +
> +       if ((cpu_logical_map(cpu) % cores) == 0) {
>                 eiointc_enable();
>
>                 for (i = 0; i < eiointc_priv[0]->vec_count / 32; i++) {
> @@ -165,7 +215,9 @@ static int eiointc_router_init(unsigned int cpu)
>
>                 for (i = 0; i < eiointc_priv[0]->vec_count / 4; i++) {
>                         /* Route to Node-0 Core-0 */
> -                       if (index == 0)
> +                       if (eiointc_priv[index]->cpu_encoded)
> +                               bit = cpu_logical_map(0);
> +                       else if (index == 0)
>                                 bit = BIT(cpu_logical_map(0));
>                         else
>                                 bit = (eiointc_priv[index]->node << 4) | 1;
> @@ -369,6 +421,7 @@ static int __init acpi_cascade_irqdomain_init(void)
>  static int __init eiointc_init(struct eiointc_priv *priv, int parent_irq,
>                                u64 node_map)
>  {
> +       u32 val;
>         int i;
>
>         node_map = node_map ? node_map : -1ULL;
> @@ -389,6 +442,17 @@ static int __init eiointc_init(struct eiointc_priv *priv, int parent_irq,
>                 return -ENOMEM;
>         }
>
> +       if (cpu_has_hypervisor) {
> +               val = iocsr_read32(EXTIOI_VIRT_FEATURES);
> +               if (val & BIT(EXTIOI_HAS_CPU_ENCODE)) {
> +                       val = iocsr_read32(EXTIOI_VIRT_CONFIG);
> +                       val |= BIT(EXTIOI_ENABLE_CPU_ENCODE);
> +                       iocsr_write32(val, EXTIOI_VIRT_CONFIG);
> +                       priv->cpu_encoded = true;
> +                       pr_info("loongson-extioi: enable cpu encodig \n");
> +               }
> +       }
> +
>         eiointc_priv[nr_pics++] = priv;
>         eiointc_router_init(0);
>         irq_set_chained_handler_and_data(parent_irq, eiointc_irq_dispatch, priv);
> --
> 2.39.3
>

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ