1 // SPDX-License-Identifier: GPL-2.0-only
3 * Multiplex several IPIs over a single HW IPI.
5 * Copyright (c) 2022 Ventana Micro Systems Inc.
8 #define pr_fmt(fmt) "riscv: " fmt
10 #include <linux/init.h>
11 #include <linux/irq.h>
12 #include <linux/irqchip/chained_irq.h>
13 #include <linux/irqdomain.h>
16 DEFINE_STATIC_KEY_FALSE(riscv_sbi_for_rfence
);
17 EXPORT_SYMBOL_GPL(riscv_sbi_for_rfence
);
19 static int sbi_ipi_virq
;
21 static void sbi_ipi_handle(struct irq_desc
*desc
)
23 struct irq_chip
*chip
= irq_desc_get_chip(desc
);
25 chained_irq_enter(chip
, desc
);
27 csr_clear(CSR_IP
, IE_SIE
);
30 chained_irq_exit(chip
, desc
);
33 static int sbi_ipi_starting_cpu(unsigned int cpu
)
35 enable_percpu_irq(sbi_ipi_virq
, irq_get_trigger_type(sbi_ipi_virq
));
39 void __init
sbi_ipi_init(void)
42 struct irq_domain
*domain
;
44 if (riscv_ipi_have_virq_range())
47 domain
= irq_find_matching_fwnode(riscv_get_intc_hwnode(),
50 pr_err("unable to find INTC IRQ domain\n");
54 sbi_ipi_virq
= irq_create_mapping(domain
, RV_IRQ_SOFT
);
56 pr_err("unable to create INTC IRQ mapping\n");
60 virq
= ipi_mux_create(BITS_PER_BYTE
, sbi_send_ipi
);
62 pr_err("unable to create muxed IPIs\n");
63 irq_dispose_mapping(sbi_ipi_virq
);
67 irq_set_chained_handler(sbi_ipi_virq
, sbi_ipi_handle
);
70 * Don't disable IPI when CPU goes offline because
71 * the masking/unmasking of virtual IPIs is done
74 cpuhp_setup_state(CPUHP_AP_IRQ_RISCV_SBI_IPI_STARTING
,
75 "irqchip/sbi-ipi:starting",
76 sbi_ipi_starting_cpu
, NULL
);
78 riscv_ipi_set_virq_range(virq
, BITS_PER_BYTE
);
79 pr_info("providing IPIs using SBI IPI extension\n");
82 * Use the SBI remote fence extension to avoid
83 * the extra context switch needed to handle IPIs.
85 static_branch_enable(&riscv_sbi_for_rfence
);