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.5 2009/11/25 14:28:50 rmind 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/malloc.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(struct device *, struct cfdata *, void *); 22 static void gemini_ipi_attach(struct device *, struct device *, 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(struct device *parent, struct cfdata *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(struct device *parent, struct device *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 = malloc(sizeof(*iqp), M_DEVBUF, M_NOWAIT|M_ZERO); 107 if (iqp == NULL) { 108 printf("gemini_ipi_intrq_insert: malloc failed\n"); 109 return NULL; 110 } 111 112 iqp->iq_func = func; 113 iqp->iq_arg = arg; 114 SIMPLEQ_INSERT_TAIL(&sc->sc_intrq, iqp, iq_q); 115 116 return (void *)iqp; 117 } 118 119 static inline void 120 gemini_ipi_intrq_remove(gemini_ipi_softc_t *sc, void *cookie) 121 { 122 gemini_ipi_intrq_t *iqp; 123 124 SIMPLEQ_FOREACH(iqp, &sc->sc_intrq, iq_q) { 125 if ((void *)iqp == cookie) { 126 SIMPLEQ_REMOVE(&sc->sc_intrq, 127 iqp, gemini_ipi_intrq, iq_q); 128 free(iqp, M_DEVBUF); 129 return; 130 } 131 } 132 } 133 134 static inline int 135 gemini_ipi_intrq_dispatch(gemini_ipi_softc_t *sc) 136 { 137 gemini_ipi_intrq_t *iqp; 138 int rv = 0; 139 140 SIMPLEQ_FOREACH(iqp, &sc->sc_intrq, iq_q) 141 rv |= (*iqp->iq_func)(iqp->iq_arg); 142 143 return (rv != 0); 144 } 145 146 147 void * 148 ipi_intr_establish(int (*func)(void *), void *arg) 149 { 150 gemini_ipi_softc_t *sc = gemini_ipi_sc; 151 void *ih; 152 153 if (sc == NULL) 154 return NULL; 155 156 ih = gemini_ipi_intrq_insert(sc, func, arg); 157 #ifdef DEBUG 158 if (ih == NULL) 159 panic("%s: gemini_ipi_intrq_insert failed", 160 device_xname(&sc->sc_dev)); 161 #endif 162 163 return ih; 164 } 165 166 void 167 ipi_intr_disestablish(void *ih) 168 { 169 gemini_ipi_softc_t *sc = gemini_ipi_sc; 170 171 if (sc == NULL) 172 panic("%s: NULL gemini_ipi_sc", device_xname(&sc->sc_dev)); 173 174 gemini_ipi_intrq_remove(sc, ih); 175 } 176 177 int 178 ipi_send(void) 179 { 180 gemini_ipi_softc_t *sc = gemini_ipi_sc; 181 uint32_t r; 182 uint32_t bit; 183 bus_addr_t off; 184 185 if (sc == NULL) 186 return -1; 187 188 #if defined(GEMINI_MASTER) 189 off = GEMINI_GLOBAL_CPU0; 190 bit = GLOBAL_CPU0_IPICPU1; 191 #elif defined(GEMINI_SLAVE) 192 off = GEMINI_GLOBAL_CPU1; 193 bit = GLOBAL_CPU1_IPICPU0; 194 #endif 195 196 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, off); 197 r |= bit; 198 bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, r); 199 200 return 0; 201 } 202 203 static inline void 204 ipi_ack(gemini_ipi_softc_t *sc) 205 { 206 uint32_t r; 207 uint32_t bit; 208 bus_addr_t off; 209 210 #if defined(GEMINI_MASTER) 211 off = GEMINI_GLOBAL_CPU1; 212 bit = GLOBAL_CPU1_IPICPU0; 213 #elif defined(GEMINI_SLAVE) 214 off = GEMINI_GLOBAL_CPU0; 215 bit = GLOBAL_CPU0_IPICPU1; 216 #endif 217 218 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, off); 219 r &= ~bit; 220 bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, r); 221 } 222 223 static int 224 gemini_ipiintr(void *arg) 225 { 226 gemini_ipi_softc_t *sc = arg; 227 int rv; 228 229 if (sc == NULL) 230 return -1; 231 232 ipi_ack(sc); 233 234 rv = gemini_ipi_intrq_dispatch(sc); 235 236 return rv; 237 } 238