Home | History | Annotate | Line # | Download | only in gemini
      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.7 2023/05/26 20:50:21 andvar 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 <arm/arm32/pte.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 master/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, CFARGS_NONE);
    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