1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Multiplex several IPIs over a single HW IPI. |
4 | * |
5 | * Copyright (c) 2022 Ventana Micro Systems Inc. |
6 | */ |
7 | |
8 | #define pr_fmt(fmt) "riscv: " fmt |
9 | #include <linux/cpu.h> |
10 | #include <linux/init.h> |
11 | #include <linux/irq.h> |
12 | #include <linux/irqchip/chained_irq.h> |
13 | #include <linux/irqdomain.h> |
14 | #include <asm/sbi.h> |
15 | |
16 | static int sbi_ipi_virq; |
17 | |
18 | static void sbi_ipi_handle(struct irq_desc *desc) |
19 | { |
20 | struct irq_chip *chip = irq_desc_get_chip(desc); |
21 | |
22 | chained_irq_enter(chip, desc); |
23 | |
24 | csr_clear(CSR_IP, IE_SIE); |
25 | ipi_mux_process(); |
26 | |
27 | chained_irq_exit(chip, desc); |
28 | } |
29 | |
30 | static int sbi_ipi_starting_cpu(unsigned int cpu) |
31 | { |
32 | enable_percpu_irq(sbi_ipi_virq, irq_get_trigger_type(irq: sbi_ipi_virq)); |
33 | return 0; |
34 | } |
35 | |
36 | void __init sbi_ipi_init(void) |
37 | { |
38 | int virq; |
39 | struct irq_domain *domain; |
40 | |
41 | if (riscv_ipi_have_virq_range()) |
42 | return; |
43 | |
44 | domain = irq_find_matching_fwnode(fwnode: riscv_get_intc_hwnode(), |
45 | bus_token: DOMAIN_BUS_ANY); |
46 | if (!domain) { |
47 | pr_err("unable to find INTC IRQ domain\n" ); |
48 | return; |
49 | } |
50 | |
51 | sbi_ipi_virq = irq_create_mapping(host: domain, hwirq: RV_IRQ_SOFT); |
52 | if (!sbi_ipi_virq) { |
53 | pr_err("unable to create INTC IRQ mapping\n" ); |
54 | return; |
55 | } |
56 | |
57 | virq = ipi_mux_create(BITS_PER_BYTE, mux_send: sbi_send_ipi); |
58 | if (virq <= 0) { |
59 | pr_err("unable to create muxed IPIs\n" ); |
60 | irq_dispose_mapping(virq: sbi_ipi_virq); |
61 | return; |
62 | } |
63 | |
64 | irq_set_chained_handler(irq: sbi_ipi_virq, handle: sbi_ipi_handle); |
65 | |
66 | /* |
67 | * Don't disable IPI when CPU goes offline because |
68 | * the masking/unmasking of virtual IPIs is done |
69 | * via generic IPI-Mux |
70 | */ |
71 | cpuhp_setup_state(state: CPUHP_AP_ONLINE_DYN, |
72 | name: "irqchip/sbi-ipi:starting" , |
73 | startup: sbi_ipi_starting_cpu, NULL); |
74 | |
75 | riscv_ipi_set_virq_range(virq, BITS_PER_BYTE, false); |
76 | pr_info("providing IPIs using SBI IPI extension\n" ); |
77 | } |
78 | |