1 #include "opt_gemini.h" 2 #if !defined(GEMINI_MASTER) && !defined(GEMINI_SLAVE) 3 # error IPI needs GEMINI_MASTER or GEMINI_SLAVE 4 #endif 5 #include "locators.h" 6 #include "geminiipm.h" 7 8 #include <sys/cdefs.h> 9 10 __KERNEL_RCSID(0, "$NetBSD: gemini_ipi.c,v 1.9 2020/11/20 18:10:07 thorpej Exp $"); 11 12 #include <sys/param.h> 13 #include <sys/systm.h> 14 #include <sys/device.h> 15 #include <sys/intr.h> 16 #include <sys/kmem.h> 17 #include <arch/arm/gemini/gemini_obiovar.h> 18 #include <arch/arm/gemini/gemini_ipivar.h> 19 #include <arch/arm/gemini/gemini_reg.h> 20 21 static int gemini_ipi_match(device_t, cfdata_t, void *); 22 static void gemini_ipi_attach(device_t, device_t, void *); 23 static int gemini_ipiintr(void *); 24 25 CFATTACH_DECL_NEW(geminiipi, sizeof(struct gemini_ipi_softc), 26 gemini_ipi_match, gemini_ipi_attach, NULL, NULL); 27 28 static gemini_ipi_softc_t *gemini_ipi_sc; 29 30 31 static int 32 gemini_ipi_match(device_t parent, cfdata_t cf, void *aux) 33 { 34 struct obio_attach_args *obio = aux; 35 36 if (obio->obio_intr == LPCCF_INTR_DEFAULT) 37 panic("ipi must specify intr in config."); 38 39 return 1; 40 } 41 42 static void 43 gemini_ipi_attach(device_t parent, device_t self, void *aux) 44 { 45 gemini_ipi_softc_t *sc = device_private(self); 46 struct obio_attach_args *obio = aux; 47 bus_space_tag_t iot; 48 bus_space_handle_t ioh; 49 bus_size_t size; 50 bus_addr_t addr; 51 void *ih; 52 53 iot = obio->obio_iot; 54 addr = GEMINI_GLOBAL_BASE; 55 size = 4096; /* XXX */ 56 57 if (bus_space_map(iot, addr, size, 0, &ioh)) 58 panic("%s: Cannot map registers", device_xname(self)); 59 60 /* 61 * NOTE: we are using IPL_NET, not IPL_HIGH use of IPI on this system 62 * is (mainly) networking keep simple (for now) and force all IPIs 63 * to same level so splnet() can block them as any other NIC. 64 */ 65 #if 0 66 ih = intr_establish(obio->obio_intr, IPL_NET, IST_LEVEL_HIGH, 67 gemini_ipiintr, sc); 68 #else 69 ih = intr_establish(obio->obio_intr, IPL_NET, IST_EDGE_RISING, 70 gemini_ipiintr, sc); 71 #endif 72 if (ih == NULL) 73 panic("%s: Cannot establish interrupt %d\n", 74 device_xname(self), obio->obio_intr); 75 76 SIMPLEQ_INIT(&sc->sc_intrq); 77 78 sc->sc_iot = iot; 79 sc->sc_ioh = ioh; 80 sc->sc_addr = addr; 81 sc->sc_size = size; 82 sc->sc_intr = obio->obio_intr; 83 sc->sc_ih = ih; 84 85 gemini_ipi_sc = sc; 86 87 aprint_normal("\n"); 88 aprint_naive("\n"); 89 90 #if NGEMINIIPM > 0 91 config_found(self, __UNCONST("geminiipm"), NULL); 92 #endif 93 } 94 95 static inline int 96 gemini_ipi_intrq_empty(gemini_ipi_softc_t *sc) 97 { 98 return SIMPLEQ_EMPTY(&sc->sc_intrq); 99 } 100 101 static inline void * 102 gemini_ipi_intrq_insert(gemini_ipi_softc_t *sc, int (*func)(void *), void *arg) 103 { 104 gemini_ipi_intrq_t *iqp; 105 106 iqp = kmem_zalloc(sizeof(*iqp), KM_SLEEP); 107 iqp->iq_func = func; 108 iqp->iq_arg = arg; 109 SIMPLEQ_INSERT_TAIL(&sc->sc_intrq, iqp, iq_q); 110 111 return (void *)iqp; 112 } 113 114 static inline void 115 gemini_ipi_intrq_remove(gemini_ipi_softc_t *sc, void *cookie) 116 { 117 gemini_ipi_intrq_t *iqp; 118 119 SIMPLEQ_FOREACH(iqp, &sc->sc_intrq, iq_q) { 120 if ((void *)iqp == cookie) { 121 SIMPLEQ_REMOVE(&sc->sc_intrq, 122 iqp, gemini_ipi_intrq, iq_q); 123 kmem_free(iqp, sizeof(*iqp)); 124 return; 125 } 126 } 127 } 128 129 static inline int 130 gemini_ipi_intrq_dispatch(gemini_ipi_softc_t *sc) 131 { 132 gemini_ipi_intrq_t *iqp; 133 int rv = 0; 134 135 SIMPLEQ_FOREACH(iqp, &sc->sc_intrq, iq_q) 136 rv |= (*iqp->iq_func)(iqp->iq_arg); 137 138 return (rv != 0); 139 } 140 141 142 void * 143 ipi_intr_establish(int (*func)(void *), void *arg) 144 { 145 gemini_ipi_softc_t *sc = gemini_ipi_sc; 146 void *ih; 147 148 if (sc == NULL) 149 return NULL; 150 151 ih = gemini_ipi_intrq_insert(sc, func, arg); 152 return ih; 153 } 154 155 void 156 ipi_intr_disestablish(void *ih) 157 { 158 gemini_ipi_softc_t *sc = gemini_ipi_sc; 159 160 if (sc == NULL) 161 panic("NULL gemini_ipi_sc"); 162 163 gemini_ipi_intrq_remove(sc, ih); 164 } 165 166 int 167 ipi_send(void) 168 { 169 gemini_ipi_softc_t *sc = gemini_ipi_sc; 170 uint32_t r; 171 uint32_t bit; 172 bus_addr_t off; 173 174 if (sc == NULL) 175 return -1; 176 177 #if defined(GEMINI_MASTER) 178 off = GEMINI_GLOBAL_CPU0; 179 bit = GLOBAL_CPU0_IPICPU1; 180 #elif defined(GEMINI_SLAVE) 181 off = GEMINI_GLOBAL_CPU1; 182 bit = GLOBAL_CPU1_IPICPU0; 183 #endif 184 185 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, off); 186 r |= bit; 187 bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, r); 188 189 return 0; 190 } 191 192 static inline void 193 ipi_ack(gemini_ipi_softc_t *sc) 194 { 195 uint32_t r; 196 uint32_t bit; 197 bus_addr_t off; 198 199 #if defined(GEMINI_MASTER) 200 off = GEMINI_GLOBAL_CPU1; 201 bit = GLOBAL_CPU1_IPICPU0; 202 #elif defined(GEMINI_SLAVE) 203 off = GEMINI_GLOBAL_CPU0; 204 bit = GLOBAL_CPU0_IPICPU1; 205 #endif 206 207 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, off); 208 r &= ~bit; 209 bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, r); 210 } 211 212 static int 213 gemini_ipiintr(void *arg) 214 { 215 gemini_ipi_softc_t *sc = arg; 216 int rv; 217 218 if (sc == NULL) 219 return -1; 220 221 ipi_ack(sc); 222 223 rv = gemini_ipi_intrq_dispatch(sc); 224 225 return rv; 226 } 227