Home | History | Annotate | Line # | Download | only in gemini
gemini_ipi.c revision 1.4.10.2
      1  1.4.10.2  yamt #include "opt_gemini.h"
      2  1.4.10.2  yamt #if !defined(GEMINI_MASTER)  && !defined(GEMINI_SLAVE)
      3  1.4.10.2  yamt # error IPI needs GEMINI_MASTER or GEMINI_SLAVE
      4  1.4.10.2  yamt #endif
      5  1.4.10.2  yamt #include "locators.h"
      6  1.4.10.2  yamt #include "geminiipm.h"
      7  1.4.10.2  yamt 
      8  1.4.10.2  yamt #include <sys/cdefs.h>
      9  1.4.10.2  yamt 
     10  1.4.10.2  yamt __KERNEL_RCSID(0, "$NetBSD: gemini_ipi.c,v 1.4.10.2 2009/05/04 08:10:41 yamt Exp $");
     11  1.4.10.2  yamt 
     12  1.4.10.2  yamt #include <sys/param.h>
     13  1.4.10.2  yamt #include <sys/systm.h>
     14  1.4.10.2  yamt #include <sys/device.h>
     15  1.4.10.2  yamt #include <sys/intr.h>
     16  1.4.10.2  yamt #include <sys/malloc.h>
     17  1.4.10.2  yamt #include <arch/arm/gemini/gemini_obiovar.h>
     18  1.4.10.2  yamt #include <arch/arm/gemini/gemini_ipivar.h>
     19  1.4.10.2  yamt #include <arch/arm/gemini/gemini_reg.h>
     20  1.4.10.2  yamt 
     21  1.4.10.2  yamt static int  gemini_ipi_match(struct device *, struct cfdata *, void *);
     22  1.4.10.2  yamt static void gemini_ipi_attach(struct device *, struct device *, void *);
     23  1.4.10.2  yamt static int  gemini_ipiintr(void *);
     24  1.4.10.2  yamt 
     25  1.4.10.2  yamt CFATTACH_DECL_NEW(geminiipi, sizeof(struct gemini_ipi_softc),
     26  1.4.10.2  yamt 	gemini_ipi_match, gemini_ipi_attach, NULL, NULL);
     27  1.4.10.2  yamt 
     28  1.4.10.2  yamt static gemini_ipi_softc_t *gemini_ipi_sc;
     29  1.4.10.2  yamt 
     30  1.4.10.2  yamt 
     31  1.4.10.2  yamt static int
     32  1.4.10.2  yamt gemini_ipi_match(struct device *parent, struct cfdata *cf, void *aux)
     33  1.4.10.2  yamt {
     34  1.4.10.2  yamt         struct obio_attach_args *obio = aux;
     35  1.4.10.2  yamt 
     36  1.4.10.2  yamt         if (obio->obio_intr == LPCCF_INTR_DEFAULT)
     37  1.4.10.2  yamt                 panic("ipi must specify intr in config.");
     38  1.4.10.2  yamt 
     39  1.4.10.2  yamt         return 1;
     40  1.4.10.2  yamt }
     41  1.4.10.2  yamt 
     42  1.4.10.2  yamt static void
     43  1.4.10.2  yamt gemini_ipi_attach(struct device *parent, struct device *self, void *aux)
     44  1.4.10.2  yamt {
     45  1.4.10.2  yamt         gemini_ipi_softc_t *sc = device_private(self);
     46  1.4.10.2  yamt         struct obio_attach_args *obio = aux;
     47  1.4.10.2  yamt 	bus_space_tag_t iot;
     48  1.4.10.2  yamt 	bus_space_handle_t ioh;
     49  1.4.10.2  yamt 	bus_size_t size;
     50  1.4.10.2  yamt 	bus_addr_t addr;
     51  1.4.10.2  yamt 	void *ih;
     52  1.4.10.2  yamt 
     53  1.4.10.2  yamt 	iot = obio->obio_iot;
     54  1.4.10.2  yamt 	addr = GEMINI_GLOBAL_BASE;
     55  1.4.10.2  yamt 	size = 4096;		/* XXX */
     56  1.4.10.2  yamt 
     57  1.4.10.2  yamt 	if (bus_space_map(iot, addr, size, 0, &ioh))
     58  1.4.10.2  yamt                 panic("%s: Cannot map registers", device_xname(self));
     59  1.4.10.2  yamt 
     60  1.4.10.2  yamt 	/*
     61  1.4.10.2  yamt 	 * NOTE we are using IPL_NET, not IPL_IPI a.k.a. IPL_HIGH
     62  1.4.10.2  yamt 	 * use of IPI on this system is (mainly) networking
     63  1.4.10.2  yamt 	 * keep simple (for now) and force all IPIs to same level
     64  1.4.10.2  yamt 	 * so splnet() can block them as any other NIC.
     65  1.4.10.2  yamt 	 */
     66  1.4.10.2  yamt #if 0
     67  1.4.10.2  yamt 	ih = intr_establish(obio->obio_intr, IPL_NET, IST_LEVEL_HIGH,
     68  1.4.10.2  yamt 		gemini_ipiintr, sc);
     69  1.4.10.2  yamt #else
     70  1.4.10.2  yamt 	ih = intr_establish(obio->obio_intr, IPL_NET, IST_EDGE_RISING,
     71  1.4.10.2  yamt 		gemini_ipiintr, sc);
     72  1.4.10.2  yamt #endif
     73  1.4.10.2  yamt 	if (ih == NULL)
     74  1.4.10.2  yamt 		panic("%s: Cannot establish interrupt %d\n",
     75  1.4.10.2  yamt 			device_xname(self), obio->obio_intr);
     76  1.4.10.2  yamt 
     77  1.4.10.2  yamt 	SIMPLEQ_INIT(&sc->sc_intrq);
     78  1.4.10.2  yamt 
     79  1.4.10.2  yamt 	sc->sc_iot = iot;
     80  1.4.10.2  yamt 	sc->sc_ioh = ioh;
     81  1.4.10.2  yamt 	sc->sc_addr = addr;
     82  1.4.10.2  yamt 	sc->sc_size = size;
     83  1.4.10.2  yamt 	sc->sc_intr = obio->obio_intr;
     84  1.4.10.2  yamt 	sc->sc_ih = ih;
     85  1.4.10.2  yamt 
     86  1.4.10.2  yamt 	gemini_ipi_sc = sc;
     87  1.4.10.2  yamt 
     88  1.4.10.2  yamt 	aprint_normal("\n");
     89  1.4.10.2  yamt 	aprint_naive("\n");
     90  1.4.10.2  yamt 
     91  1.4.10.2  yamt #if NGEMINIIPM > 0
     92  1.4.10.2  yamt 	config_found(self, __UNCONST("geminiipm"), NULL);
     93  1.4.10.2  yamt #endif
     94  1.4.10.2  yamt }
     95  1.4.10.2  yamt 
     96  1.4.10.2  yamt static inline int
     97  1.4.10.2  yamt gemini_ipi_intrq_empty(gemini_ipi_softc_t *sc)
     98  1.4.10.2  yamt {
     99  1.4.10.2  yamt 	return SIMPLEQ_EMPTY(&sc->sc_intrq);
    100  1.4.10.2  yamt }
    101  1.4.10.2  yamt 
    102  1.4.10.2  yamt static inline void *
    103  1.4.10.2  yamt gemini_ipi_intrq_insert(gemini_ipi_softc_t *sc, int (*func)(void *), void *arg)
    104  1.4.10.2  yamt {
    105  1.4.10.2  yamt 	gemini_ipi_intrq_t *iqp;
    106  1.4.10.2  yamt 
    107  1.4.10.2  yamt         iqp = malloc(sizeof(*iqp), M_DEVBUF, M_NOWAIT|M_ZERO);
    108  1.4.10.2  yamt         if (iqp == NULL) {
    109  1.4.10.2  yamt 		printf("gemini_ipi_intrq_insert: malloc failed\n");
    110  1.4.10.2  yamt 		return NULL;
    111  1.4.10.2  yamt 	}
    112  1.4.10.2  yamt 
    113  1.4.10.2  yamt         iqp->iq_func = func;
    114  1.4.10.2  yamt         iqp->iq_arg = arg;
    115  1.4.10.2  yamt         SIMPLEQ_INSERT_TAIL(&sc->sc_intrq, iqp, iq_q);
    116  1.4.10.2  yamt 
    117  1.4.10.2  yamt 	return (void *)iqp;
    118  1.4.10.2  yamt }
    119  1.4.10.2  yamt 
    120  1.4.10.2  yamt static inline void
    121  1.4.10.2  yamt gemini_ipi_intrq_remove(gemini_ipi_softc_t *sc, void *cookie)
    122  1.4.10.2  yamt {
    123  1.4.10.2  yamt 	gemini_ipi_intrq_t *iqp;
    124  1.4.10.2  yamt 
    125  1.4.10.2  yamt 	SIMPLEQ_FOREACH(iqp, &sc->sc_intrq, iq_q) {
    126  1.4.10.2  yamt 		if ((void *)iqp == cookie) {
    127  1.4.10.2  yamt 			SIMPLEQ_REMOVE(&sc->sc_intrq,
    128  1.4.10.2  yamt 				iqp, gemini_ipi_intrq, iq_q);
    129  1.4.10.2  yamt 			free(iqp, M_DEVBUF);
    130  1.4.10.2  yamt 			return;
    131  1.4.10.2  yamt 		}
    132  1.4.10.2  yamt 	}
    133  1.4.10.2  yamt }
    134  1.4.10.2  yamt 
    135  1.4.10.2  yamt static inline int
    136  1.4.10.2  yamt gemini_ipi_intrq_dispatch(gemini_ipi_softc_t *sc)
    137  1.4.10.2  yamt {
    138  1.4.10.2  yamt 	gemini_ipi_intrq_t *iqp;
    139  1.4.10.2  yamt 	int rv = 0;
    140  1.4.10.2  yamt 
    141  1.4.10.2  yamt 	SIMPLEQ_FOREACH(iqp, &sc->sc_intrq, iq_q)
    142  1.4.10.2  yamt 		rv |= (*iqp->iq_func)(iqp->iq_arg);
    143  1.4.10.2  yamt 
    144  1.4.10.2  yamt 	return (rv != 0);
    145  1.4.10.2  yamt }
    146  1.4.10.2  yamt 
    147  1.4.10.2  yamt 
    148  1.4.10.2  yamt void *
    149  1.4.10.2  yamt ipi_intr_establish(int (*func)(void *), void *arg)
    150  1.4.10.2  yamt {
    151  1.4.10.2  yamt         gemini_ipi_softc_t *sc = gemini_ipi_sc;
    152  1.4.10.2  yamt 	void *ih;
    153  1.4.10.2  yamt 
    154  1.4.10.2  yamt 	if (sc == NULL)
    155  1.4.10.2  yamt 		return NULL;
    156  1.4.10.2  yamt 
    157  1.4.10.2  yamt 	ih = gemini_ipi_intrq_insert(sc, func, arg);
    158  1.4.10.2  yamt #ifdef DEBUG
    159  1.4.10.2  yamt         if (ih == NULL)
    160  1.4.10.2  yamt 		panic("%s: gemini_ipi_intrq_insert failed",
    161  1.4.10.2  yamt 			device_xname(&sc->sc_dev));
    162  1.4.10.2  yamt #endif
    163  1.4.10.2  yamt 
    164  1.4.10.2  yamt 	return ih;
    165  1.4.10.2  yamt }
    166  1.4.10.2  yamt 
    167  1.4.10.2  yamt void
    168  1.4.10.2  yamt ipi_intr_disestablish(void *ih)
    169  1.4.10.2  yamt {
    170  1.4.10.2  yamt         gemini_ipi_softc_t *sc = gemini_ipi_sc;
    171  1.4.10.2  yamt 
    172  1.4.10.2  yamt 	if (sc == NULL)
    173  1.4.10.2  yamt 		panic("%s: NULL gemini_ipi_sc", device_xname(&sc->sc_dev));
    174  1.4.10.2  yamt 
    175  1.4.10.2  yamt         gemini_ipi_intrq_remove(sc, ih);
    176  1.4.10.2  yamt }
    177  1.4.10.2  yamt 
    178  1.4.10.2  yamt int
    179  1.4.10.2  yamt ipi_send(void)
    180  1.4.10.2  yamt {
    181  1.4.10.2  yamt         gemini_ipi_softc_t *sc = gemini_ipi_sc;
    182  1.4.10.2  yamt 	uint32_t r;
    183  1.4.10.2  yamt 	uint32_t bit;
    184  1.4.10.2  yamt 	bus_addr_t off;
    185  1.4.10.2  yamt 
    186  1.4.10.2  yamt 	if (sc == NULL)
    187  1.4.10.2  yamt 		return -1;
    188  1.4.10.2  yamt 
    189  1.4.10.2  yamt #if defined(GEMINI_MASTER)
    190  1.4.10.2  yamt 	off = GEMINI_GLOBAL_CPU0;
    191  1.4.10.2  yamt 	bit = GLOBAL_CPU0_IPICPU1;
    192  1.4.10.2  yamt #elif defined(GEMINI_SLAVE)
    193  1.4.10.2  yamt 	off = GEMINI_GLOBAL_CPU1;
    194  1.4.10.2  yamt 	bit = GLOBAL_CPU1_IPICPU0;
    195  1.4.10.2  yamt #endif
    196  1.4.10.2  yamt 
    197  1.4.10.2  yamt 	r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, off);
    198  1.4.10.2  yamt 	r |= bit;
    199  1.4.10.2  yamt 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, r);
    200  1.4.10.2  yamt 
    201  1.4.10.2  yamt 	return 0;
    202  1.4.10.2  yamt }
    203  1.4.10.2  yamt 
    204  1.4.10.2  yamt static inline void
    205  1.4.10.2  yamt ipi_ack(gemini_ipi_softc_t *sc)
    206  1.4.10.2  yamt {
    207  1.4.10.2  yamt 	uint32_t r;
    208  1.4.10.2  yamt 	uint32_t bit;
    209  1.4.10.2  yamt 	bus_addr_t off;
    210  1.4.10.2  yamt 
    211  1.4.10.2  yamt #if defined(GEMINI_MASTER)
    212  1.4.10.2  yamt 	off = GEMINI_GLOBAL_CPU1;
    213  1.4.10.2  yamt 	bit = GLOBAL_CPU1_IPICPU0;
    214  1.4.10.2  yamt #elif defined(GEMINI_SLAVE)
    215  1.4.10.2  yamt 	off = GEMINI_GLOBAL_CPU0;
    216  1.4.10.2  yamt 	bit = GLOBAL_CPU0_IPICPU1;
    217  1.4.10.2  yamt #endif
    218  1.4.10.2  yamt 
    219  1.4.10.2  yamt 	r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, off);
    220  1.4.10.2  yamt 	r &= ~bit;
    221  1.4.10.2  yamt 	bus_space_write_4(sc->sc_iot, sc->sc_ioh, off, r);
    222  1.4.10.2  yamt }
    223  1.4.10.2  yamt 
    224  1.4.10.2  yamt static int
    225  1.4.10.2  yamt gemini_ipiintr(void *arg)
    226  1.4.10.2  yamt {
    227  1.4.10.2  yamt 	gemini_ipi_softc_t *sc = arg;
    228  1.4.10.2  yamt 	int rv;
    229  1.4.10.2  yamt 
    230  1.4.10.2  yamt 	if (sc == NULL)
    231  1.4.10.2  yamt 		return -1;
    232  1.4.10.2  yamt 
    233  1.4.10.2  yamt 	ipi_ack(sc);
    234  1.4.10.2  yamt 
    235  1.4.10.2  yamt 	rv = gemini_ipi_intrq_dispatch(sc);
    236  1.4.10.2  yamt 
    237  1.4.10.2  yamt 	return rv;
    238  1.4.10.2  yamt }
    239