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 "gpn.h" 7 8 #include <sys/cdefs.h> 9 10 __KERNEL_RCSID(0, "$NetBSD: gemini_ipi.c,v 1.2 2008/11/26 05:25:27 matt 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_IPI a.k.a. IPL_HIGH 62 * use of IPI on this system is (mainly) networking 63 * keep simple (for now) and force all IPIs to same level 64 * so splnet() can block them as any other NIC. 65 */ 66 #if 0 67 ih = intr_establish(obio->obio_intr, IPL_NET, IST_LEVEL_HIGH, 68 gemini_ipiintr, sc); 69 #else 70 ih = intr_establish(obio->obio_intr, IPL_NET, IST_EDGE_RISING, 71 gemini_ipiintr, sc); 72 #endif 73 if (ih == NULL) 74 panic("%s: Cannot establish interrupt %d\n", 75 device_xname(self), obio->obio_intr); 76 77 SIMPLEQ_INIT(&sc->sc_intrq); 78 79 sc->sc_iot = iot; 80 sc->sc_ioh = ioh; 81 sc->sc_addr = addr; 82 sc->sc_size = size; 83 sc->sc_intr = obio->obio_intr; 84 sc->sc_ih = ih; 85 86 gemini_ipi_sc = sc; 87 88 aprint_normal("\n"); 89 aprint_naive("\n"); 90 91 #if NGNP > 0 92 config_found(self, "gnp", NULL); 93 #endif 94 } 95 96 static inline int 97 gemini_ipi_intrq_empty(gemini_ipi_softc_t *sc) 98 { 99 return SIMPLEQ_EMPTY(&sc->sc_intrq); 100 } 101 102 static inline void * 103 gemini_ipi_intrq_insert(gemini_ipi_softc_t *sc, int (*func)(void *), void *arg) 104 { 105 gemini_ipi_intrq_t *iqp; 106 107 iqp = malloc(sizeof(*iqp), M_DEVBUF, M_NOWAIT|M_ZERO); 108 if (iqp == NULL) { 109 printf("gemini_ipi_intrq_insert: malloc failed\n"); 110 return NULL; 111 } 112 113 iqp->iq_func = func; 114 iqp->iq_arg = arg; 115 SIMPLEQ_INSERT_TAIL(&sc->sc_intrq, iqp, iq_q); 116 117 return (void *)iqp; 118 } 119 120 static inline void 121 gemini_ipi_intrq_remove(gemini_ipi_softc_t *sc, void *cookie) 122 { 123 gemini_ipi_intrq_t *iqp; 124 125 SIMPLEQ_FOREACH(iqp, &sc->sc_intrq, iq_q) { 126 if ((void *)iqp == cookie) { 127 SIMPLEQ_REMOVE(&sc->sc_intrq, 128 iqp, gemini_ipi_intrq, iq_q); 129 free(iqp, M_DEVBUF); 130 return; 131 } 132 } 133 } 134 135 static inline int 136 gemini_ipi_intrq_dispatch(gemini_ipi_softc_t *sc) 137 { 138 gemini_ipi_intrq_t *iqp; 139 int rv = 0; 140 141 SIMPLEQ_FOREACH(iqp, &sc->sc_intrq, iq_q) 142 rv |= (*iqp->iq_func)(iqp->iq_arg); 143 144 return (rv != 0); 145 } 146 147 148 void * 149 ipi_intr_establish(int (*func)(void *), void *arg) 150 { 151 gemini_ipi_softc_t *sc = gemini_ipi_sc; 152 void *ih; 153 154 if (sc == NULL) 155 return NULL; 156 157 ih = gemini_ipi_intrq_insert(sc, func, arg); 158 #ifdef DEBUG 159 if (ih == NULL) 160 panic("%s: gemini_ipi_intrq_insert failed", 161 device_xname(&sc->sc_dev)); 162 #endif 163 164 return ih; 165 } 166 167 void 168 ipi_intr_disestablish(void *ih) 169 { 170 gemini_ipi_softc_t *sc = gemini_ipi_sc; 171 172 if (sc == NULL) 173 panic("%s: NULL gemini_ipi_sc", device_xname(&sc->sc_dev)); 174 175 gemini_ipi_intrq_remove(sc, ih); 176 } 177 178 int 179 ipi_send(void) 180 { 181 gemini_ipi_softc_t *sc = gemini_ipi_sc; 182 uint32_t r; 183 uint32_t bit; 184 bus_addr_t off; 185 186 if (sc == NULL) 187 return -1; 188 189 #if defined(GEMINI_MASTER) 190 off = GEMINI_GLOBAL_CPU0; 191 bit = GLOBAL_CPU0_IPICPU1; 192 #elif defined(GEMINI_SLAVE) 193 off = GEMINI_GLOBAL_CPU1; 194 bit = GLOBAL_CPU1_IPICPU0; 195 #endif 196 197 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, off); 198 r |= bit; 199 bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, r); 200 201 return 0; 202 } 203 204 static inline void 205 ipi_ack(gemini_ipi_softc_t *sc) 206 { 207 uint32_t r; 208 uint32_t bit; 209 bus_addr_t off; 210 211 #if defined(GEMINI_MASTER) 212 off = GEMINI_GLOBAL_CPU1; 213 bit = GLOBAL_CPU1_IPICPU0; 214 #elif defined(GEMINI_SLAVE) 215 off = GEMINI_GLOBAL_CPU0; 216 bit = GLOBAL_CPU0_IPICPU1; 217 #endif 218 219 r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, off); 220 r &= ~bit; 221 bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, r); 222 } 223 224 static int 225 gemini_ipiintr(void *arg) 226 { 227 gemini_ipi_softc_t *sc = arg; 228 int rv; 229 230 if (sc == NULL) 231 return -1; 232 233 ipi_ack(sc); 234 235 rv = gemini_ipi_intrq_dispatch(sc); 236 237 return rv; 238 } 239