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_ipm.c,v 1.2 2012/10/27 17:17:38 chs 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 <arm/cpufunc.h> 18 #include <arch/arm/gemini/gemini_obiovar.h> 19 #include <arch/arm/gemini/gemini_ipivar.h> 20 #include <arch/arm/gemini/gemini_ipm.h> 21 #include <arch/arm/gemini/gemini_ipmvar.h> 22 #include <evbarm/gemini/gemini.h> 23 24 // #define IPMDEBUG 25 #if defined IPMDEBUG 26 static int ipmdebug; 27 # define DPRINTFN(n, x) do { if ((n) >= ipmdebug) printf x ; } while (1) 28 #else 29 # define DPRINTFN(n, x) 30 #endif 31 32 typedef struct dispatch_entry { 33 unsigned int ipl; 34 size_t quota; 35 void *arg; 36 void (*consume)(void *, const void *); 37 void (*counter)(void *, size_t); 38 #ifdef NOTYET 39 void *sih; /* softint handle */ 40 #endif 41 } ipm_dispatch_entry_t; 42 43 typedef struct gemini_ipm_softc { 44 device_t sc_dev; 45 void *sc_ih; 46 ipm_queue_t *sc_rxqueue; 47 ipm_queue_t *sc_txqueue; 48 size_t sc_txqavail; /* quota available */ 49 unsigned long long sc_rxcount; 50 unsigned long long sc_txcount; 51 ipm_dispatch_entry_t sc_dispatch_tab[256]; 52 } gemini_ipm_softc_t; 53 54 55 static int gemini_ipm_match(device_t, cfdata_t, void *); 56 static void gemini_ipm_attach(device_t, device_t, void *); 57 static int gemini_ipm_intr(void *); 58 static void gemini_ipm_count_txdone(gemini_ipm_softc_t *); 59 60 61 CFATTACH_DECL_NEW(geminiipm, sizeof(struct gemini_ipm_softc), 62 gemini_ipm_match, gemini_ipm_attach, NULL, NULL); 63 64 gemini_ipm_softc_t *gemini_ipm_sc = NULL; 65 66 67 /* 68 * copy from shared queue to private copy 69 * SW coherency would go here if desc_src were in cached mem 70 */ 71 static inline void 72 gemini_ipm_desc_read(ipm_desc_t *desc_dst, const ipm_desc_t *desc_src) 73 { 74 extern void gpn_print_gd(const void *); /* XXX DEBUG */ 75 DPRINTFN(2, ("%s: %p %p\n", __FUNCTION__, desc_dst, desc_src)); 76 #ifdef IPMDEBUG 77 if (ipmdebug >= 3) 78 gpn_print_gd(desc_src); 79 #endif 80 *desc_dst = *desc_src; 81 KASSERT(desc_dst->tag != IPM_TAG_NONE); 82 } 83 84 /* 85 * copy from private copy to shared queue 86 * SW coherency would go here if desc_dst were in cached mem 87 */ 88 static inline void 89 gemini_ipm_desc_write(ipm_desc_t *desc_dst, const ipm_desc_t *desc_src) 90 { 91 extern void gpn_print_gd(const void *); /* XXX DEBUG */ 92 DPRINTFN(2, ("%s: %p %p\n", __FUNCTION__, desc_dst, desc_src)); 93 #ifdef IPMDEBUG 94 if (ipmdebug >= 3) 95 gpn_print_gd(desc_src); 96 #endif 97 KASSERT(desc_src->tag != IPM_TAG_NONE); 98 *desc_dst = *desc_src; 99 } 100 101 102 static int 103 gemini_ipm_match(device_t parent, cfdata_t cf, void *aux) 104 { 105 char *name = aux; 106 107 if (strcmp(name, "geminiipm") != 0) 108 return 0; 109 110 return 1; 111 } 112 113 static void 114 gemini_ipm_attach(device_t parent, device_t self, void *aux) 115 { 116 gemini_ipm_softc_t *sc = device_private(self); 117 void *ih; 118 119 sc->sc_dev = self; 120 ih = ipi_intr_establish(gemini_ipm_intr, sc); 121 if (ih == NULL) 122 panic("%s: Cannot establish IPI interrupt\n", 123 device_xname(self)); 124 sc->sc_ih = ih; 125 memset(&sc->sc_dispatch_tab, 0, sizeof(sc->sc_dispatch_tab)); 126 127 128 /* 129 * queues are flipped tx/rx for mater/slave 130 */ 131 KASSERT(GEMINI_IPMQ_SIZE == (2 * sizeof(ipm_queue_t))); 132 #if defined(GEMINI_MASTER) 133 sc->sc_rxqueue = (ipm_queue_t *)GEMINI_IPMQ_VBASE; 134 sc->sc_txqueue = sc->sc_rxqueue + 1; 135 memset(sc->sc_rxqueue, 0, sizeof(ipm_queue_t)); 136 memset(sc->sc_txqueue, 0, sizeof(ipm_queue_t)); 137 #elif defined(GEMINI_SLAVE) 138 sc->sc_txqueue = (ipm_queue_t *)GEMINI_IPMQ_VBASE; 139 sc->sc_rxqueue = sc->sc_txqueue + 1; 140 #else 141 # error one of GEMINI_MASTER or GEMINI_SLAVE must be defined 142 #endif 143 sc->sc_txqavail = NIPMDESC; 144 145 sc->sc_rxcount = 0LL; 146 sc->sc_txcount = 0LL; 147 148 gemini_ipm_sc = sc; 149 150 aprint_normal("\n"); 151 aprint_naive("\n"); 152 153 #if NGPN > 0 154 config_found(self, __UNCONST("gpn"), NULL); 155 #endif 156 } 157 158 void * 159 gemini_ipm_register(uint8_t tag, unsigned int ipl, size_t quota, 160 void (*consume)(void *, const void *), 161 void (*counter)(void *, size_t), 162 void *arg) 163 { 164 gemini_ipm_softc_t *sc = gemini_ipm_sc; 165 ipm_dispatch_entry_t *disp; 166 void *ipmh = NULL; 167 int psw; 168 169 DPRINTFN(1, ("%s:%d: %d %d %ld %p %p %p\n", __FUNCTION__, __LINE__, 170 tag, ipl, quota, consume, counter, arg)); 171 if (sc == NULL) 172 return NULL; /* not attached yet */ 173 174 if (tag == 0) 175 return NULL; /* tag #0 is reserved */ 176 177 psw = disable_interrupts(I32_bit); 178 disp = &sc->sc_dispatch_tab[tag]; 179 if (disp->consume == 0) { 180 if (sc->sc_txqavail >= quota) { 181 sc->sc_txqavail -= quota; 182 disp->ipl = ipl; 183 disp->consume = consume; 184 disp->counter = counter; 185 disp->arg = arg; 186 #ifdef NOTYET 187 if (ipl > SOFTINT_LVLMASK) 188 panic("%s: bad level %d", 189 device_xname(sc->sc_dev), ipl); 190 disp->sih = softint_establish(ipl, consume, arg); 191 #endif 192 ipmh = disp; 193 } 194 } 195 restore_interrupts(psw); 196 197 return ipmh; 198 } 199 200 void 201 gemini_ipm_deregister(void *ipmh) 202 { 203 gemini_ipm_softc_t *sc = gemini_ipm_sc; 204 ipm_dispatch_entry_t *disp = ipmh; 205 int psw; 206 207 if (sc == NULL) 208 return; 209 210 psw = disable_interrupts(I32_bit); 211 memset(disp, 0, sizeof(*disp)); 212 #ifdef NOTYET 213 softint_disestablish(sc->sih); 214 #endif 215 restore_interrupts(psw); 216 } 217 218 static inline int 219 gemini_ipm_dispatch(gemini_ipm_softc_t *sc) 220 { 221 ipm_dispatch_entry_t *disp; 222 ipm_desc_t desc; 223 ipmqindex_t ix_read; 224 ipmqindex_t ix_write; 225 int rv = 0; 226 227 ix_read = sc->sc_rxqueue->ix_read; 228 ix_write = sc->sc_rxqueue->ix_write; 229 230 if (! ipmqisempty(ix_read, ix_write)) { 231 rv = 1; 232 do { 233 gemini_ipm_desc_read(&desc, 234 &sc->sc_rxqueue->ipm_desc[ix_read]); 235 ix_read = ipmqnext(ix_read); 236 KASSERT(desc.tag != IPM_TAG_NONE); 237 disp = &sc->sc_dispatch_tab[desc.tag]; 238 #ifdef NOTYET 239 softint_schedule(disp->sih); 240 #else 241 (*disp->consume)(disp->arg, &desc); 242 #endif 243 ix_write = sc->sc_rxqueue->ix_write; 244 sc->sc_rxqueue->ix_read = ix_read; 245 sc->sc_rxcount++; 246 } while (! ipmqisempty(ix_read, ix_write)); 247 } else { 248 DPRINTFN(1, ("%s: ipmqisempty %d %d\n", 249 __FUNCTION__, ix_read, ix_write)); 250 } 251 return rv; 252 } 253 254 static int 255 gemini_ipm_intr(void *arg) 256 { 257 gemini_ipm_softc_t *sc = arg; 258 int rv; 259 260 rv = gemini_ipm_dispatch(sc); 261 gemini_ipm_count_txdone(sc); 262 263 return rv; 264 } 265 266 int 267 gemini_ipm_produce(const void *adescp, size_t ndesc) 268 { 269 const ipm_desc_t *descp = adescp; 270 gemini_ipm_softc_t *sc = gemini_ipm_sc; 271 ipmqindex_t ix_read; 272 ipmqindex_t ix_write; 273 274 KASSERT(ndesc == 1); /* XXX TMP */ 275 276 DPRINTFN(2, ("%s:%d: %p %ld, tag %d\n", 277 __FUNCTION__, __LINE__, descp, ndesc, descp->tag)); 278 ix_read = sc->sc_txqueue->ix_read; 279 ix_write = sc->sc_txqueue->ix_write; 280 if (ipmqisfull(ix_read, ix_write)) { 281 /* we expect this to "never" happen; check your quotas */ 282 panic("%s: queue full\n", device_xname(sc->sc_dev)); 283 } 284 gemini_ipm_desc_write(&sc->sc_txqueue->ipm_desc[ix_write], descp); 285 sc->sc_txqueue->ix_write = ipmqnext(ix_write); 286 sc->sc_txcount++; 287 288 ipi_send(); 289 290 gemini_ipm_count_txdone(sc); 291 292 return 0; 293 } 294 295 static void * 296 gemini_ba_to_va(bus_addr_t ba) 297 { 298 return (void *)(GEMINI_ALLMEM_VBASE + ba); 299 } 300 301 void 302 gemini_ipm_copyin(void *dst, bus_addr_t ba, size_t len) 303 { 304 void *src; 305 306 DPRINTFN(2, ("%s:%d: %p %#lx %ld\n", 307 __FUNCTION__, __LINE__, dst, ba, len)); 308 src = gemini_ba_to_va(ba); 309 memcpy(dst, src, len); 310 cpu_dcache_inv_range((vaddr_t)src, len); 311 } 312 313 314 static void 315 gemini_ipm_count_txdone(gemini_ipm_softc_t *sc) 316 { 317 ipmqindex_t count = 0; /* XXX must count per tag */ 318 ipm_dispatch_entry_t *disp; 319 ipmqindex_t ixr = sc->sc_txqueue->ix_read; 320 uint8_t tag = IPM_TAG_GPN; 321 static ipmqindex_t oixr = 0; 322 323 while (oixr != ixr) { 324 oixr = ipmqnext(oixr); 325 count++; 326 } 327 if (count != 0) { 328 disp = &sc->sc_dispatch_tab[tag]; 329 (*disp->counter)(disp->arg, count); 330 } 331 } 332 333 void gemini_ipm_stats_print(void); 334 void 335 gemini_ipm_stats_print(void) 336 { 337 gemini_ipm_softc_t *sc = gemini_ipm_sc; 338 339 printf("rxcount %lld, txcount %lld\n", sc->sc_rxcount, sc->sc_txcount); 340 } 341