xref: /openbsd-src/sys/arch/octeon/dev/octeon_intr.c (revision 0dd6b0da8efbf470b8a65d2b781c8d5600638374)
1*0dd6b0daSvisa /*	$OpenBSD: octeon_intr.c,v 1.25 2019/03/17 05:25:06 visa Exp $	*/
2f177a60aSvisa 
361e15267Ssyuu /*
461e15267Ssyuu  * Copyright (c) 2000-2004 Opsycon AB  (www.opsycon.se)
561e15267Ssyuu  *
661e15267Ssyuu  * Redistribution and use in source and binary forms, with or without
761e15267Ssyuu  * modification, are permitted provided that the following conditions
861e15267Ssyuu  * are met:
961e15267Ssyuu  * 1. Redistributions of source code must retain the above copyright
1061e15267Ssyuu  *    notice, this list of conditions and the following disclaimer.
1161e15267Ssyuu  * 2. Redistributions in binary form must reproduce the above copyright
1261e15267Ssyuu  *    notice, this list of conditions and the following disclaimer in the
1361e15267Ssyuu  *    documentation and/or other materials provided with the distribution.
1461e15267Ssyuu  *
1561e15267Ssyuu  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
1661e15267Ssyuu  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
1761e15267Ssyuu  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1861e15267Ssyuu  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
1961e15267Ssyuu  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2061e15267Ssyuu  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2161e15267Ssyuu  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2261e15267Ssyuu  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2361e15267Ssyuu  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2461e15267Ssyuu  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2561e15267Ssyuu  * SUCH DAMAGE.
2661e15267Ssyuu  *
2761e15267Ssyuu  */
2861e15267Ssyuu 
2961e15267Ssyuu /*
3061e15267Ssyuu  * Interrupt support for Octeon Processor.
3161e15267Ssyuu  */
3261e15267Ssyuu 
3361e15267Ssyuu #include <sys/param.h>
3461e15267Ssyuu #include <sys/systm.h>
3561e15267Ssyuu #include <sys/malloc.h>
3661e15267Ssyuu 
37207b97a1Svisa #include <dev/ofw/openfirm.h>
38207b97a1Svisa 
3961e15267Ssyuu #include <machine/autoconf.h>
4061e15267Ssyuu #include <machine/intr.h>
4161e15267Ssyuu 
4289182934Svisa struct intr_handle {
4389182934Svisa 	struct intr_controller	*ih_ic;
4489182934Svisa 	void			*ih_ih;
457706e62dSvisa };
467706e62dSvisa 
4789182934Svisa struct intr_controller *octeon_ic;
4861e15267Ssyuu 
4989182934Svisa LIST_HEAD(, intr_controller) octeon_ic_list =
5089182934Svisa 	LIST_HEAD_INITIALIZER(octeon_ic_list);
5161e15267Ssyuu 
5289182934Svisa void
octeon_intr_register(struct intr_controller * ic)5389182934Svisa octeon_intr_register(struct intr_controller *ic)
5489182934Svisa {
5589182934Svisa 	struct intr_controller *tmp;
5661e15267Ssyuu 
5789182934Svisa 	/* Assume the first controller to register is the root. */
5889182934Svisa 	if (octeon_ic == NULL)
5989182934Svisa 		octeon_ic = ic;
6061e15267Ssyuu 
6189182934Svisa 	ic->ic_phandle = OF_getpropint(ic->ic_node, "phandle", 0);
6289182934Svisa 	if (ic->ic_phandle == 0)
6389182934Svisa 		return;
6461e15267Ssyuu 
6589182934Svisa 	LIST_FOREACH(tmp, &octeon_ic_list, ic_list) {
6689182934Svisa 		if (tmp->ic_phandle == ic->ic_phandle) {
6789182934Svisa 			printf("%s: node %d: duplicate phandle %d\n",
6889182934Svisa 			    __func__, ic->ic_node, ic->ic_phandle);
6989182934Svisa 			return;
7089182934Svisa 		}
7189182934Svisa 	}
72aec33009Svisa 
7389182934Svisa 	LIST_INSERT_HEAD(&octeon_ic_list, ic, ic_list);
7489182934Svisa }
75aec33009Svisa 
7661e15267Ssyuu void
octeon_intr_init(void)7761e15267Ssyuu octeon_intr_init(void)
7861e15267Ssyuu {
7989182934Svisa 	octeon_ic->ic_init();
8061e15267Ssyuu }
8161e15267Ssyuu 
8261e15267Ssyuu /*
8361e15267Ssyuu  * Establish an interrupt handler called from the dispatcher.
8461e15267Ssyuu  * The interrupt function established should return zero if there was nothing
8561e15267Ssyuu  * to serve (no int) and non-zero when an interrupt was serviced.
8661e15267Ssyuu  */
8761e15267Ssyuu void *
octeon_intr_establish(int irq,int level,int (* ih_fun)(void *),void * ih_arg,const char * ih_what)8861e15267Ssyuu octeon_intr_establish(int irq, int level,
8961e15267Ssyuu     int (*ih_fun)(void *), void *ih_arg, const char *ih_what)
9061e15267Ssyuu {
91a12b3618Svisa 	struct intr_controller *ic = octeon_ic;
92a12b3618Svisa 	struct intr_handle *ih;
93a12b3618Svisa 	void *handler;
94a12b3618Svisa 
95a12b3618Svisa 	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
96a12b3618Svisa 	if (ih == NULL)
97a12b3618Svisa 		return NULL;
98a12b3618Svisa 
99a12b3618Svisa 	handler = ic->ic_establish(irq, level, ih_fun, ih_arg, ih_what);
100a12b3618Svisa 	if (handler == NULL) {
101a12b3618Svisa 		free(ih, M_DEVBUF, sizeof(*ih));
102a12b3618Svisa 		return NULL;
103a12b3618Svisa 	}
104a12b3618Svisa 
105a12b3618Svisa 	ih->ih_ic = ic;
106a12b3618Svisa 	ih->ih_ih = handler;
107a12b3618Svisa 
108a12b3618Svisa 	return ih;
10961e15267Ssyuu }
11061e15267Ssyuu 
111207b97a1Svisa void *
octeon_intr_establish_fdt(int node,int level,int (* ih_fun)(void *),void * ih_arg,const char * ih_what)112e6dd8ec3Svisa octeon_intr_establish_fdt(int node, int level,
113e6dd8ec3Svisa     int (*ih_fun)(void *), void *ih_arg, const char *ih_what)
114e6dd8ec3Svisa {
115e6dd8ec3Svisa 	return octeon_intr_establish_fdt_idx(node, 0, level, ih_fun,
116e6dd8ec3Svisa 	    ih_arg, ih_what);
117e6dd8ec3Svisa }
118e6dd8ec3Svisa 
119e6dd8ec3Svisa void *
octeon_intr_establish_fdt_idx(int node,int idx,int level,int (* ih_fun)(void *),void * ih_arg,const char * ih_what)120207b97a1Svisa octeon_intr_establish_fdt_idx(int node, int idx, int level,
121207b97a1Svisa     int (*ih_fun)(void *), void *ih_arg, const char *ih_what)
122207b97a1Svisa {
12389182934Svisa 	struct intr_controller *ic = NULL;
12489182934Svisa 	struct intr_handle *ih;
12589182934Svisa 	void *handler;
12689182934Svisa 	int phandle;
127207b97a1Svisa 
12889182934Svisa 	phandle = OF_getpropint(node, "interrupt-parent", 1);
12989182934Svisa 	if (phandle < 1)
130207b97a1Svisa 		return NULL;
131207b97a1Svisa 
13289182934Svisa 	LIST_FOREACH(ic, &octeon_ic_list, ic_list) {
13389182934Svisa 		if (ic->ic_phandle == phandle)
134fe5d9ffbSvisa 			break;
135fe5d9ffbSvisa 	}
13689182934Svisa 	if (ic == NULL)
13789182934Svisa 		return NULL;
13889182934Svisa 
13989182934Svisa 	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT);
14089182934Svisa 	if (ih == NULL)
14189182934Svisa 		return NULL;
14289182934Svisa 
14389182934Svisa 	handler = ic->ic_establish_fdt_idx(ic->ic_cookie, node, idx, level,
14489182934Svisa 	    ih_fun, ih_arg, ih_what);
14589182934Svisa 	if (handler == NULL) {
146fe5d9ffbSvisa 		free(ih, M_DEVBUF, sizeof(*ih));
14789182934Svisa 		return NULL;
14889182934Svisa 	}
149fe5d9ffbSvisa 
15089182934Svisa 	ih->ih_ic = ic;
15189182934Svisa 	ih->ih_ih = handler;
152a12b3618Svisa 
15389182934Svisa 	return ih;
15461e15267Ssyuu }
15561e15267Ssyuu 
15661e15267Ssyuu void
octeon_intr_disestablish(void * cookie)15789182934Svisa octeon_intr_disestablish(void *cookie)
158e6dd8ec3Svisa {
15989182934Svisa 	struct intr_handle *ih = cookie;
16089182934Svisa 	struct intr_controller *ic = ih->ih_ic;
16161e15267Ssyuu 
16289182934Svisa 	ic->ic_disestablish(ih->ih_ih);
16389182934Svisa 	free(ih, M_DEVBUF, sizeof(*ih));
16461e15267Ssyuu }
165aec33009Svisa 
166a12b3618Svisa void
octeon_intr_disestablish_fdt(void * cookie)167a12b3618Svisa octeon_intr_disestablish_fdt(void *cookie)
168a12b3618Svisa {
169a12b3618Svisa 	octeon_intr_disestablish(cookie);
170a12b3618Svisa }
171a12b3618Svisa 
172cae6d111Svisa void
intr_barrier(void * cookie)173cae6d111Svisa intr_barrier(void *cookie)
174cae6d111Svisa {
175*0dd6b0daSvisa 	struct intr_handle *ih = cookie;
176*0dd6b0daSvisa 	struct intr_controller *ic = ih->ih_ic;
177*0dd6b0daSvisa 
178*0dd6b0daSvisa 	ic->ic_intr_barrier(ih->ih_ih);
179cae6d111Svisa }
180cae6d111Svisa 
181aec33009Svisa #ifdef MULTIPROCESSOR
182aec33009Svisa /*
183aec33009Svisa  * Inter-processor interrupt control logic.
184aec33009Svisa  */
185aec33009Svisa 
186aec33009Svisa int
hw_ipi_intr_establish(int (* func)(void *),u_long cpuid)187aec33009Svisa hw_ipi_intr_establish(int (*func)(void *), u_long cpuid)
188aec33009Svisa {
18989182934Svisa 	return octeon_ic->ic_ipi_establish(func, cpuid);
19089182934Svisa }
191aec33009Svisa 
192aec33009Svisa void
hw_ipi_intr_set(u_long cpuid)193aec33009Svisa hw_ipi_intr_set(u_long cpuid)
194aec33009Svisa {
19589182934Svisa 	octeon_ic->ic_ipi_set(cpuid);
196aec33009Svisa }
197aec33009Svisa 
198aec33009Svisa void
hw_ipi_intr_clear(u_long cpuid)199aec33009Svisa hw_ipi_intr_clear(u_long cpuid)
200aec33009Svisa {
20189182934Svisa 	octeon_ic->ic_ipi_clear(cpuid);
202aec33009Svisa }
203aec33009Svisa #endif /* MULTIPROCESSOR */
204