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