xref: /openbsd/sys/dev/fdt/qcsmptp.c (revision d467fd9e)
1*d467fd9eSpatrick /*	$OpenBSD: qcsmptp.c,v 1.2 2023/07/04 14:32:21 patrick Exp $	*/
20b5b3cbdSpatrick /*
30b5b3cbdSpatrick  * Copyright (c) 2023 Patrick Wildt <patrick@blueri.se>
40b5b3cbdSpatrick  *
50b5b3cbdSpatrick  * Permission to use, copy, modify, and distribute this software for any
60b5b3cbdSpatrick  * purpose with or without fee is hereby granted, provided that the above
70b5b3cbdSpatrick  * copyright notice and this permission notice appear in all copies.
80b5b3cbdSpatrick  *
90b5b3cbdSpatrick  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
100b5b3cbdSpatrick  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
110b5b3cbdSpatrick  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
120b5b3cbdSpatrick  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
130b5b3cbdSpatrick  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
140b5b3cbdSpatrick  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
150b5b3cbdSpatrick  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
160b5b3cbdSpatrick  */
170b5b3cbdSpatrick 
180b5b3cbdSpatrick #include <sys/param.h>
190b5b3cbdSpatrick #include <sys/systm.h>
200b5b3cbdSpatrick #include <sys/device.h>
210b5b3cbdSpatrick #include <sys/malloc.h>
220b5b3cbdSpatrick #include <sys/atomic.h>
230b5b3cbdSpatrick 
240b5b3cbdSpatrick #include <machine/bus.h>
250b5b3cbdSpatrick #include <machine/fdt.h>
260b5b3cbdSpatrick 
270b5b3cbdSpatrick #include <dev/ofw/openfirm.h>
280b5b3cbdSpatrick #include <dev/ofw/ofw_misc.h>
290b5b3cbdSpatrick #include <dev/ofw/fdt.h>
300b5b3cbdSpatrick 
310b5b3cbdSpatrick #define SMP2P_MAX_ENTRY		16
320b5b3cbdSpatrick #define SMP2P_MAX_ENTRY_NAME	16
330b5b3cbdSpatrick 
340b5b3cbdSpatrick struct qcsmptp_smem_item {
350b5b3cbdSpatrick 	uint32_t magic;
360b5b3cbdSpatrick #define SMP2P_MAGIC			0x504d5324
370b5b3cbdSpatrick 	uint8_t version;
380b5b3cbdSpatrick #define SMP2P_VERSION			1
390b5b3cbdSpatrick 	unsigned features:24;
400b5b3cbdSpatrick #define SMP2P_FEATURE_SSR_ACK		(1 << 0)
410b5b3cbdSpatrick 	uint16_t local_pid;
420b5b3cbdSpatrick 	uint16_t remote_pid;
430b5b3cbdSpatrick 	uint16_t total_entries;
440b5b3cbdSpatrick 	uint16_t valid_entries;
450b5b3cbdSpatrick 	uint32_t flags;
460b5b3cbdSpatrick #define SMP2P_FLAGS_RESTART_DONE	(1 << 0)
470b5b3cbdSpatrick #define SMP2P_FLAGS_RESTART_ACK		(1 << 1)
480b5b3cbdSpatrick 
490b5b3cbdSpatrick 	struct {
500b5b3cbdSpatrick 		uint8_t name[SMP2P_MAX_ENTRY_NAME];
510b5b3cbdSpatrick 		uint32_t value;
520b5b3cbdSpatrick 	} entries[SMP2P_MAX_ENTRY];
530b5b3cbdSpatrick } __packed;
540b5b3cbdSpatrick 
550b5b3cbdSpatrick struct qcsmptp_intrhand {
560b5b3cbdSpatrick 	TAILQ_ENTRY(qcsmptp_intrhand) ih_q;
570b5b3cbdSpatrick 	int (*ih_func)(void *);
580b5b3cbdSpatrick 	void *ih_arg;
590b5b3cbdSpatrick 	void *ih_ic;
600b5b3cbdSpatrick 	int ih_pin;
610b5b3cbdSpatrick 	int ih_enabled;
620b5b3cbdSpatrick };
630b5b3cbdSpatrick 
640b5b3cbdSpatrick struct qcsmptp_interrupt_controller {
650b5b3cbdSpatrick 	TAILQ_HEAD(,qcsmptp_intrhand) ic_intrq;
660b5b3cbdSpatrick 	struct qcsmptp_softc *ic_sc;
670b5b3cbdSpatrick 	struct interrupt_controller ic_ic;
680b5b3cbdSpatrick };
690b5b3cbdSpatrick 
700b5b3cbdSpatrick struct qcsmptp_entry {
710b5b3cbdSpatrick 	TAILQ_ENTRY(qcsmptp_entry) e_q;
720b5b3cbdSpatrick 	char *e_name;
730b5b3cbdSpatrick 	int e_namelen;
740b5b3cbdSpatrick 	uint32_t *e_value;
750b5b3cbdSpatrick 	uint32_t e_last_value;
760b5b3cbdSpatrick 	struct qcsmptp_interrupt_controller *e_ic;
770b5b3cbdSpatrick };
780b5b3cbdSpatrick 
790b5b3cbdSpatrick struct qcsmptp_softc {
800b5b3cbdSpatrick 	struct device		sc_dev;
810b5b3cbdSpatrick 	int			sc_node;
820b5b3cbdSpatrick 	void			*sc_ih;
830b5b3cbdSpatrick 
840b5b3cbdSpatrick 	uint16_t		sc_local_pid;
850b5b3cbdSpatrick 	uint16_t		sc_remote_pid;
860b5b3cbdSpatrick 	uint32_t		sc_smem_id[2];
870b5b3cbdSpatrick 
880b5b3cbdSpatrick 	struct qcsmptp_smem_item *sc_in;
890b5b3cbdSpatrick 	struct qcsmptp_smem_item *sc_out;
900b5b3cbdSpatrick 
910b5b3cbdSpatrick 	TAILQ_HEAD(,qcsmptp_entry) sc_inboundq;
920b5b3cbdSpatrick 	TAILQ_HEAD(,qcsmptp_entry) sc_outboundq;
930b5b3cbdSpatrick 
940b5b3cbdSpatrick 	int			sc_negotiated;
950b5b3cbdSpatrick 	int			sc_ssr_ack_enabled;
960b5b3cbdSpatrick 	int			sc_ssr_ack;
970b5b3cbdSpatrick 
980b5b3cbdSpatrick 	uint16_t		sc_valid_entries;
990b5b3cbdSpatrick 
1000b5b3cbdSpatrick 	struct mbox_channel	*sc_mc;
1010b5b3cbdSpatrick };
1020b5b3cbdSpatrick 
1030b5b3cbdSpatrick int	qcsmptp_match(struct device *, void *, void *);
1040b5b3cbdSpatrick void	qcsmptp_attach(struct device *, struct device *, void *);
1050b5b3cbdSpatrick void	qcsmptp_deferred(struct device *);
1060b5b3cbdSpatrick 
1070b5b3cbdSpatrick const struct cfattach qcsmptp_ca = {
1080b5b3cbdSpatrick 	sizeof (struct qcsmptp_softc), qcsmptp_match, qcsmptp_attach
1090b5b3cbdSpatrick };
1100b5b3cbdSpatrick 
1110b5b3cbdSpatrick struct cfdriver qcsmptp_cd = {
1120b5b3cbdSpatrick 	NULL, "qcsmptp", DV_DULL
1130b5b3cbdSpatrick };
1140b5b3cbdSpatrick 
1150b5b3cbdSpatrick int	qcsmptp_intr(void *);
1160b5b3cbdSpatrick void	*qcsmptp_intr_establish(void *, int *, int, struct cpu_info *,
1170b5b3cbdSpatrick 	    int (*)(void *), void *, char *);
1180b5b3cbdSpatrick void	qcsmptp_intr_disestablish(void *);
1190b5b3cbdSpatrick void	qcsmptp_intr_enable(void *);
1200b5b3cbdSpatrick void	qcsmptp_intr_disable(void *);
1210b5b3cbdSpatrick void	qcsmptp_intr_barrier(void *);
1220b5b3cbdSpatrick 
1230b5b3cbdSpatrick extern int qcsmem_alloc(int, int, int);
1240b5b3cbdSpatrick extern void *qcsmem_get(int, int, int *);
1250b5b3cbdSpatrick 
1260b5b3cbdSpatrick int
qcsmptp_match(struct device * parent,void * match,void * aux)1270b5b3cbdSpatrick qcsmptp_match(struct device *parent, void *match, void *aux)
1280b5b3cbdSpatrick {
1290b5b3cbdSpatrick 	struct fdt_attach_args *faa = aux;
1300b5b3cbdSpatrick 
1310b5b3cbdSpatrick 	return OF_is_compatible(faa->fa_node, "qcom,smp2p");
1320b5b3cbdSpatrick }
1330b5b3cbdSpatrick 
1340b5b3cbdSpatrick void
qcsmptp_attach(struct device * parent,struct device * self,void * aux)1350b5b3cbdSpatrick qcsmptp_attach(struct device *parent, struct device *self, void *aux)
1360b5b3cbdSpatrick {
1370b5b3cbdSpatrick 	struct qcsmptp_softc *sc = (struct qcsmptp_softc *)self;
1380b5b3cbdSpatrick 	struct fdt_attach_args *faa = aux;
1390b5b3cbdSpatrick 
1400b5b3cbdSpatrick 	sc->sc_node = faa->fa_node;
1410b5b3cbdSpatrick 
1420b5b3cbdSpatrick 	TAILQ_INIT(&sc->sc_inboundq);
1430b5b3cbdSpatrick 	TAILQ_INIT(&sc->sc_outboundq);
1440b5b3cbdSpatrick 
1450b5b3cbdSpatrick 	sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_BIO,
1460b5b3cbdSpatrick 	    qcsmptp_intr, sc, sc->sc_dev.dv_xname);
1470b5b3cbdSpatrick 	if (sc->sc_ih == NULL) {
1480b5b3cbdSpatrick 		printf(": can't establish interrupt\n");
1490b5b3cbdSpatrick 		return;
1500b5b3cbdSpatrick 	}
1510b5b3cbdSpatrick 
1520b5b3cbdSpatrick 	sc->sc_local_pid = OF_getpropint(faa->fa_node,
1530b5b3cbdSpatrick 	    "qcom,local-pid", 0xffff);
1540b5b3cbdSpatrick 	sc->sc_remote_pid = OF_getpropint(faa->fa_node,
1550b5b3cbdSpatrick 	    "qcom,remote-pid", 0xffff);
1560b5b3cbdSpatrick 	if (sc->sc_local_pid == 0xffff || sc->sc_remote_pid == 0xffff) {
1570b5b3cbdSpatrick 		printf(": can't get pids\n");
1580b5b3cbdSpatrick 		return;
1590b5b3cbdSpatrick 	}
1600b5b3cbdSpatrick 
1610b5b3cbdSpatrick 	if (OF_getpropintarray(faa->fa_node, "qcom,smem", sc->sc_smem_id,
1620b5b3cbdSpatrick 	    sizeof(sc->sc_smem_id)) != sizeof(sc->sc_smem_id)) {
1630b5b3cbdSpatrick 		printf(": can't get smem property \n");
1640b5b3cbdSpatrick 		return;
1650b5b3cbdSpatrick 	}
1660b5b3cbdSpatrick 
1670b5b3cbdSpatrick 	printf("\n");
1680b5b3cbdSpatrick 
1690b5b3cbdSpatrick 	config_defer(self, qcsmptp_deferred);
1700b5b3cbdSpatrick }
1710b5b3cbdSpatrick 
1720b5b3cbdSpatrick void
qcsmptp_deferred(struct device * self)1730b5b3cbdSpatrick qcsmptp_deferred(struct device *self)
1740b5b3cbdSpatrick {
1750b5b3cbdSpatrick 	struct qcsmptp_softc *sc = (struct qcsmptp_softc *)self;
1760b5b3cbdSpatrick 	struct qcsmptp_entry *e;
1770b5b3cbdSpatrick 	int node, size;
1780b5b3cbdSpatrick 
1790b5b3cbdSpatrick 	sc->sc_mc = mbox_channel_idx(sc->sc_node, 0, NULL);
1800b5b3cbdSpatrick 	if (sc->sc_mc == NULL) {
1810b5b3cbdSpatrick 		printf(": can't get mailbox\n");
1820b5b3cbdSpatrick 		return;
1830b5b3cbdSpatrick 	}
1840b5b3cbdSpatrick 
185*d467fd9eSpatrick 	if (qcsmem_alloc(sc->sc_remote_pid, sc->sc_smem_id[0],
186*d467fd9eSpatrick 	    sizeof(*sc->sc_in)) != 0) {
187*d467fd9eSpatrick 		printf(": can't alloc smp2p item\n");
188*d467fd9eSpatrick 		return;
189*d467fd9eSpatrick 	}
190*d467fd9eSpatrick 
191*d467fd9eSpatrick 	sc->sc_in = qcsmem_get(sc->sc_remote_pid, sc->sc_smem_id[0], NULL);
192*d467fd9eSpatrick 	if (sc->sc_in == NULL) {
193*d467fd9eSpatrick 		printf(": can't get smp2p item\n");
194*d467fd9eSpatrick 		return;
195*d467fd9eSpatrick 	}
196*d467fd9eSpatrick 
1970b5b3cbdSpatrick 	if (qcsmem_alloc(sc->sc_remote_pid, sc->sc_smem_id[1],
1980b5b3cbdSpatrick 	    sizeof(*sc->sc_out)) != 0) {
1990b5b3cbdSpatrick 		printf(": can't alloc smp2p item\n");
2000b5b3cbdSpatrick 		return;
2010b5b3cbdSpatrick 	}
2020b5b3cbdSpatrick 
2030b5b3cbdSpatrick 	sc->sc_out = qcsmem_get(sc->sc_remote_pid, sc->sc_smem_id[1], NULL);
2040b5b3cbdSpatrick 	if (sc->sc_out == NULL) {
2050b5b3cbdSpatrick 		printf(": can't get smp2p item\n");
2060b5b3cbdSpatrick 		return;
2070b5b3cbdSpatrick 	}
2080b5b3cbdSpatrick 
2090b5b3cbdSpatrick 	memset(sc->sc_out, 0, sizeof(*sc->sc_out));
2100b5b3cbdSpatrick 	sc->sc_out->magic = SMP2P_MAGIC;
2110b5b3cbdSpatrick 	sc->sc_out->local_pid = sc->sc_local_pid;
2120b5b3cbdSpatrick 	sc->sc_out->remote_pid = sc->sc_remote_pid;
2130b5b3cbdSpatrick 	sc->sc_out->total_entries = SMP2P_MAX_ENTRY;
2140b5b3cbdSpatrick 	sc->sc_out->features = SMP2P_FEATURE_SSR_ACK;
2150b5b3cbdSpatrick 	membar_sync();
2160b5b3cbdSpatrick 	sc->sc_out->version = SMP2P_VERSION;
2170b5b3cbdSpatrick 	mbox_send(sc->sc_mc, NULL, 0);
2180b5b3cbdSpatrick 
2190b5b3cbdSpatrick 	for (node = OF_child(sc->sc_node); node; node = OF_peer(node)) {
2200b5b3cbdSpatrick 		size = OF_getproplen(node, "qcom,entry-name");
2210b5b3cbdSpatrick 		if (size <= 0)
2220b5b3cbdSpatrick 			continue;
2230b5b3cbdSpatrick 		e = malloc(sizeof(*e), M_DEVBUF, M_WAITOK | M_ZERO);
2240b5b3cbdSpatrick 		e->e_namelen = size;
2250b5b3cbdSpatrick 		e->e_name = malloc(e->e_namelen, M_DEVBUF, M_WAITOK);
2260b5b3cbdSpatrick 		OF_getprop(node, "qcom,entry-name", e->e_name,
2270b5b3cbdSpatrick 		    e->e_namelen);
2280b5b3cbdSpatrick 		e->e_name[e->e_namelen - 1] = '\0';
2290b5b3cbdSpatrick 
2300b5b3cbdSpatrick 		if (OF_getproplen(node, "interrupt-controller") == 0) {
2310b5b3cbdSpatrick 			struct qcsmptp_interrupt_controller *ic;
2320b5b3cbdSpatrick 			ic = malloc(sizeof(*ic), M_DEVBUF, M_WAITOK | M_ZERO);
2330b5b3cbdSpatrick 			TAILQ_INIT(&ic->ic_intrq);
2340b5b3cbdSpatrick 			ic->ic_sc = sc;
2350b5b3cbdSpatrick 			ic->ic_ic.ic_node = node;
2360b5b3cbdSpatrick 			ic->ic_ic.ic_cookie = ic;
2370b5b3cbdSpatrick 			ic->ic_ic.ic_establish = qcsmptp_intr_establish;
2380b5b3cbdSpatrick 			ic->ic_ic.ic_disestablish = qcsmptp_intr_disestablish;
2390b5b3cbdSpatrick 			ic->ic_ic.ic_enable = qcsmptp_intr_enable;
2400b5b3cbdSpatrick 			ic->ic_ic.ic_disable = qcsmptp_intr_disable;
2410b5b3cbdSpatrick 			ic->ic_ic.ic_barrier = qcsmptp_intr_barrier;
2420b5b3cbdSpatrick 			fdt_intr_register(&ic->ic_ic);
2430b5b3cbdSpatrick 			e->e_ic = ic;
2440b5b3cbdSpatrick 			TAILQ_INSERT_TAIL(&sc->sc_inboundq, e, e_q);
2450b5b3cbdSpatrick 		} else {
2460b5b3cbdSpatrick 			if (sc->sc_out->valid_entries >= SMP2P_MAX_ENTRY)
2470b5b3cbdSpatrick 				continue;
2480b5b3cbdSpatrick 
2490b5b3cbdSpatrick 			strlcpy(sc->sc_out->entries[sc->sc_out->valid_entries].name,
2500b5b3cbdSpatrick 			    e->e_name, SMP2P_MAX_ENTRY_NAME);
2510b5b3cbdSpatrick 			e->e_value = &sc->sc_out->entries[sc->sc_out->valid_entries].value;
2520b5b3cbdSpatrick 			sc->sc_out->valid_entries++;
2530b5b3cbdSpatrick 			TAILQ_INSERT_TAIL(&sc->sc_outboundq, e, e_q);
2540b5b3cbdSpatrick 
2550b5b3cbdSpatrick 			/* TODO: provide as smem state */
2560b5b3cbdSpatrick 		}
2570b5b3cbdSpatrick 	}
2580b5b3cbdSpatrick }
2590b5b3cbdSpatrick 
2600b5b3cbdSpatrick int
qcsmptp_intr(void * arg)2610b5b3cbdSpatrick qcsmptp_intr(void *arg)
2620b5b3cbdSpatrick {
2630b5b3cbdSpatrick 	struct qcsmptp_softc *sc = arg;
2640b5b3cbdSpatrick 	struct qcsmptp_entry *e;
2650b5b3cbdSpatrick 	struct qcsmptp_intrhand *ih;
2660b5b3cbdSpatrick 	uint32_t changed, val;
2670b5b3cbdSpatrick 	int do_ack = 0, i;
2680b5b3cbdSpatrick 
2690b5b3cbdSpatrick 	/* Do initial feature negotiation if inbound is new. */
2700b5b3cbdSpatrick 	if (!sc->sc_negotiated) {
2710b5b3cbdSpatrick 		if (sc->sc_in->version != sc->sc_out->version)
2720b5b3cbdSpatrick 			return 1;
2730b5b3cbdSpatrick 		sc->sc_out->features &= sc->sc_in->features;
2740b5b3cbdSpatrick 		if (sc->sc_out->features & SMP2P_FEATURE_SSR_ACK)
2750b5b3cbdSpatrick 			sc->sc_ssr_ack_enabled = 1;
2760b5b3cbdSpatrick 		sc->sc_negotiated = 1;
2770b5b3cbdSpatrick 	}
2780b5b3cbdSpatrick 	if (!sc->sc_negotiated)
2790b5b3cbdSpatrick 		return 1;
2800b5b3cbdSpatrick 
2810b5b3cbdSpatrick 	/* Use ACK mechanism if negotiated. */
2820b5b3cbdSpatrick 	if (sc->sc_ssr_ack_enabled &&
2830b5b3cbdSpatrick 	    !!(sc->sc_in->flags & SMP2P_FLAGS_RESTART_DONE) != sc->sc_ssr_ack)
2840b5b3cbdSpatrick 		do_ack = 1;
2850b5b3cbdSpatrick 
2860b5b3cbdSpatrick 	/* Catch up on new inbound entries that got added in the meantime. */
2870b5b3cbdSpatrick 	for (i = sc->sc_valid_entries; i < sc->sc_in->valid_entries; i++) {
2880b5b3cbdSpatrick 		TAILQ_FOREACH(e, &sc->sc_inboundq, e_q) {
2890b5b3cbdSpatrick 			if (strncmp(sc->sc_in->entries[i].name, e->e_name,
2900b5b3cbdSpatrick 			    SMP2P_MAX_ENTRY_NAME) != 0)
2910b5b3cbdSpatrick 				continue;
2920b5b3cbdSpatrick 			e->e_value = &sc->sc_in->entries[i].value;
2930b5b3cbdSpatrick 		}
2940b5b3cbdSpatrick 	}
2950b5b3cbdSpatrick 	sc->sc_valid_entries = i;
2960b5b3cbdSpatrick 
2970b5b3cbdSpatrick 	/* For each inbound "interrupt controller". */
2980b5b3cbdSpatrick 	TAILQ_FOREACH(e, &sc->sc_inboundq, e_q) {
2990b5b3cbdSpatrick 		if (e->e_value == NULL)
3000b5b3cbdSpatrick 			continue;
3010b5b3cbdSpatrick 		val = *e->e_value;
3020b5b3cbdSpatrick 		if (val == e->e_last_value)
3030b5b3cbdSpatrick 			continue;
3040b5b3cbdSpatrick 		changed = val ^ e->e_last_value;
3050b5b3cbdSpatrick 		e->e_last_value = val;
3060b5b3cbdSpatrick 		TAILQ_FOREACH(ih, &e->e_ic->ic_intrq, ih_q) {
3070b5b3cbdSpatrick 			if (!ih->ih_enabled)
3080b5b3cbdSpatrick 				continue;
3090b5b3cbdSpatrick 			if ((changed & (1 << ih->ih_pin)) == 0)
3100b5b3cbdSpatrick 				continue;
3110b5b3cbdSpatrick 			ih->ih_func(ih->ih_arg);
3120b5b3cbdSpatrick 		}
3130b5b3cbdSpatrick 	}
3140b5b3cbdSpatrick 
3150b5b3cbdSpatrick 	if (do_ack) {
3160b5b3cbdSpatrick 		sc->sc_ssr_ack = !sc->sc_ssr_ack;
3170b5b3cbdSpatrick 		if (sc->sc_ssr_ack)
3180b5b3cbdSpatrick 			sc->sc_out->flags |= SMP2P_FLAGS_RESTART_ACK;
3190b5b3cbdSpatrick 		else
3200b5b3cbdSpatrick 			sc->sc_out->flags &= ~SMP2P_FLAGS_RESTART_ACK;
3210b5b3cbdSpatrick 		membar_sync();
3220b5b3cbdSpatrick 		mbox_send(sc->sc_mc, NULL, 0);
3230b5b3cbdSpatrick 	}
3240b5b3cbdSpatrick 
3250b5b3cbdSpatrick 	return 1;
3260b5b3cbdSpatrick }
3270b5b3cbdSpatrick 
3280b5b3cbdSpatrick void *
qcsmptp_intr_establish(void * cookie,int * cells,int ipl,struct cpu_info * ci,int (* func)(void *),void * arg,char * name)3290b5b3cbdSpatrick qcsmptp_intr_establish(void *cookie, int *cells, int ipl,
3300b5b3cbdSpatrick     struct cpu_info *ci, int (*func)(void *), void *arg, char *name)
3310b5b3cbdSpatrick {
3320b5b3cbdSpatrick 	struct qcsmptp_interrupt_controller *ic = cookie;
3330b5b3cbdSpatrick 	struct qcsmptp_softc *sc = ic->ic_sc;
3340b5b3cbdSpatrick 	struct qcsmptp_intrhand *ih;
3350b5b3cbdSpatrick 
3360b5b3cbdSpatrick 	ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK | M_ZERO);
3370b5b3cbdSpatrick 	ih->ih_func = func;
3380b5b3cbdSpatrick 	ih->ih_arg = arg;
3390b5b3cbdSpatrick 	ih->ih_ic = ic;
3400b5b3cbdSpatrick 	ih->ih_pin = cells[0];
3410b5b3cbdSpatrick 	TAILQ_INSERT_TAIL(&ic->ic_intrq, ih, ih_q);
3420b5b3cbdSpatrick 
3430b5b3cbdSpatrick 	qcsmptp_intr_enable(ih);
3440b5b3cbdSpatrick 
3450b5b3cbdSpatrick 	if (ipl & IPL_WAKEUP)
3460b5b3cbdSpatrick 		intr_set_wakeup(sc->sc_ih);
3470b5b3cbdSpatrick 
3480b5b3cbdSpatrick 	return ih;
3490b5b3cbdSpatrick }
3500b5b3cbdSpatrick 
3510b5b3cbdSpatrick void
qcsmptp_intr_disestablish(void * cookie)3520b5b3cbdSpatrick qcsmptp_intr_disestablish(void *cookie)
3530b5b3cbdSpatrick {
3540b5b3cbdSpatrick 	struct qcsmptp_intrhand *ih = cookie;
3550b5b3cbdSpatrick 	struct qcsmptp_interrupt_controller *ic = ih->ih_ic;
3560b5b3cbdSpatrick 
3570b5b3cbdSpatrick 	qcsmptp_intr_disable(ih);
3580b5b3cbdSpatrick 
3590b5b3cbdSpatrick 	TAILQ_REMOVE(&ic->ic_intrq, ih, ih_q);
3600b5b3cbdSpatrick 	free(ih, M_DEVBUF, sizeof(*ih));
3610b5b3cbdSpatrick }
3620b5b3cbdSpatrick 
3630b5b3cbdSpatrick void
qcsmptp_intr_enable(void * cookie)3640b5b3cbdSpatrick qcsmptp_intr_enable(void *cookie)
3650b5b3cbdSpatrick {
3660b5b3cbdSpatrick 	struct qcsmptp_intrhand *ih = cookie;
3670b5b3cbdSpatrick 
3680b5b3cbdSpatrick 	ih->ih_enabled = 1;
3690b5b3cbdSpatrick }
3700b5b3cbdSpatrick 
3710b5b3cbdSpatrick void
qcsmptp_intr_disable(void * cookie)3720b5b3cbdSpatrick qcsmptp_intr_disable(void *cookie)
3730b5b3cbdSpatrick {
3740b5b3cbdSpatrick 	struct qcsmptp_intrhand *ih = cookie;
3750b5b3cbdSpatrick 
3760b5b3cbdSpatrick 	ih->ih_enabled = 0;
3770b5b3cbdSpatrick }
3780b5b3cbdSpatrick 
3790b5b3cbdSpatrick void
qcsmptp_intr_barrier(void * cookie)3800b5b3cbdSpatrick qcsmptp_intr_barrier(void *cookie)
3810b5b3cbdSpatrick {
3820b5b3cbdSpatrick 	struct qcsmptp_intrhand *ih = cookie;
3830b5b3cbdSpatrick 	struct qcsmptp_interrupt_controller *ic = ih->ih_ic;
3840b5b3cbdSpatrick 	struct qcsmptp_softc *sc = ic->ic_sc;
3850b5b3cbdSpatrick 
3860b5b3cbdSpatrick 	intr_barrier(sc->sc_ih);
3870b5b3cbdSpatrick }
388