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