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