1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2021 Jessica Clarke <jrtc27@FreeBSD.org> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/param.h> 29 #include <sys/systm.h> 30 #include <sys/bus.h> 31 #include <sys/cpuset.h> 32 #include <sys/kernel.h> 33 #include <sys/module.h> 34 #include <sys/rman.h> 35 36 #include <machine/intr.h> 37 #include <machine/sbi.h> 38 #include <machine/smp.h> 39 40 #include <dev/ofw/openfirm.h> 41 #include <dev/ofw/ofw_bus.h> 42 #include <dev/ofw/ofw_bus_subr.h> 43 44 #include "pic_if.h" 45 46 struct sbi_ipi_softc { 47 device_t dev; 48 struct resource *irq_res; 49 void *ih; 50 struct intr_irqsrc isrc; 51 uint32_t pending_ipis[MAXCPU]; 52 }; 53 54 static void 55 sbi_ipi_pic_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus, 56 u_int ipi) 57 { 58 struct sbi_ipi_softc *sc; 59 struct pcpu *pc; 60 u_long mask; 61 u_int cpu; 62 63 sc = device_get_softc(dev); 64 65 KASSERT(isrc == &sc->isrc, ("%s: not the IPI isrc", __func__)); 66 KASSERT(ipi < INTR_IPI_COUNT, 67 ("%s: not a valid IPI: %u", __func__, ipi)); 68 69 mask = 0; 70 STAILQ_FOREACH(pc, &cpuhead, pc_allcpu) { 71 cpu = pc->pc_cpuid; 72 if (CPU_ISSET(cpu, &cpus)) { 73 atomic_set_32(&sc->pending_ipis[cpu], 1u << ipi); 74 mask |= (1ul << pc->pc_hart); 75 } 76 } 77 sbi_send_ipi(&mask); 78 } 79 80 static int 81 sbi_ipi_pic_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp) 82 { 83 struct sbi_ipi_softc *sc; 84 85 sc = device_get_softc(dev); 86 87 KASSERT(ipi < INTR_IPI_COUNT, 88 ("%s: not a valid IPI: %u", __func__, ipi)); 89 90 *isrcp = &sc->isrc; 91 92 return (0); 93 94 } 95 96 static int 97 sbi_ipi_intr(void *arg) 98 { 99 struct sbi_ipi_softc *sc; 100 uint32_t ipi_bitmap; 101 u_int cpu, ipi; 102 int bit; 103 104 sc = arg; 105 106 csr_clear(sip, SIP_SSIP); 107 108 cpu = PCPU_GET(cpuid); 109 110 mb(); 111 112 ipi_bitmap = atomic_readandclear_32(&sc->pending_ipis[cpu]); 113 if (ipi_bitmap == 0) 114 return (FILTER_HANDLED); 115 116 mb(); 117 118 while ((bit = ffs(ipi_bitmap))) { 119 ipi = (bit - 1); 120 ipi_bitmap &= ~(1u << ipi); 121 122 intr_ipi_dispatch(ipi); 123 } 124 125 return (FILTER_HANDLED); 126 } 127 128 static int 129 sbi_ipi_probe(device_t dev) 130 { 131 device_set_desc(dev, "RISC-V SBI Inter-Processor Interrupts"); 132 133 return (BUS_PROBE_NOWILDCARD); 134 } 135 136 static int 137 sbi_ipi_attach(device_t dev) 138 { 139 struct sbi_ipi_softc *sc; 140 const char *name; 141 int irq, rid, error; 142 phandle_t iparent; 143 pcell_t cell; 144 145 sc = device_get_softc(dev); 146 sc->dev = dev; 147 148 memset(sc->pending_ipis, 0, sizeof(sc->pending_ipis)); 149 150 name = device_get_nameunit(dev); 151 error = intr_isrc_register(&sc->isrc, sc->dev, INTR_ISRCF_IPI, 152 "%s,ipi", name); 153 if (error != 0) { 154 device_printf(dev, "Can't register interrupt: %d\n", error); 155 return (ENXIO); 156 } 157 158 iparent = OF_xref_from_node(ofw_bus_get_node(intr_irq_root_dev)); 159 cell = IRQ_SOFTWARE_SUPERVISOR; 160 irq = ofw_bus_map_intr(dev, iparent, 1, &cell); 161 error = bus_set_resource(dev, SYS_RES_IRQ, 0, irq, 1); 162 if (error != 0) { 163 device_printf(dev, "Unable to register IRQ resource\n"); 164 return (ENXIO); 165 } 166 167 rid = 0; 168 sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, 169 RF_ACTIVE | RF_SHAREABLE); 170 if (sc->irq_res == NULL) { 171 device_printf(dev, "Unable to alloc IRQ resource\n"); 172 return (ENXIO); 173 } 174 175 error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_CLK, 176 sbi_ipi_intr, NULL, sc, &sc->ih); 177 if (error != 0) { 178 device_printf(dev, "Unable to setup IRQ resource\n"); 179 return (ENXIO); 180 } 181 182 /* TODO: Define a set of priorities once other IPI sources exist */ 183 error = intr_ipi_pic_register(dev, 0); 184 if (error != 0) { 185 device_printf(dev, "Can't register as IPI source: %d\n", error); 186 return (ENXIO); 187 } 188 189 return (0); 190 } 191 192 static device_method_t sbi_ipi_methods[] = { 193 /* Device interface */ 194 DEVMETHOD(device_probe, sbi_ipi_probe), 195 DEVMETHOD(device_attach, sbi_ipi_attach), 196 197 /* Interrupt controller interface */ 198 DEVMETHOD(pic_ipi_send, sbi_ipi_pic_ipi_send), 199 DEVMETHOD(pic_ipi_setup, sbi_ipi_pic_ipi_setup), 200 201 DEVMETHOD_END 202 }; 203 204 DEFINE_CLASS_0(sbi_ipi, sbi_ipi_driver, sbi_ipi_methods, 205 sizeof(struct sbi_ipi_softc)); 206 /* Local interrupt controller attaches during BUS_PASS_ORDER_FIRST */ 207 EARLY_DRIVER_MODULE(sbi_ipi, sbi, sbi_ipi_driver, 0, 0, 208 BUS_PASS_INTERRUPT + BUS_PASS_ORDER_EARLY); 209