1 /* $OpenBSD: octeon_intr.c,v 1.25 2019/03/17 05:25:06 visa Exp $ */ 2 3 /* 4 * Copyright (c) 2000-2004 Opsycon AB (www.opsycon.se) 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS 16 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 */ 28 29 /* 30 * Interrupt support for Octeon Processor. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/malloc.h> 36 37 #include <dev/ofw/openfirm.h> 38 39 #include <machine/autoconf.h> 40 #include <machine/intr.h> 41 42 struct intr_handle { 43 struct intr_controller *ih_ic; 44 void *ih_ih; 45 }; 46 47 struct intr_controller *octeon_ic; 48 49 LIST_HEAD(, intr_controller) octeon_ic_list = 50 LIST_HEAD_INITIALIZER(octeon_ic_list); 51 52 void 53 octeon_intr_register(struct intr_controller *ic) 54 { 55 struct intr_controller *tmp; 56 57 /* Assume the first controller to register is the root. */ 58 if (octeon_ic == NULL) 59 octeon_ic = ic; 60 61 ic->ic_phandle = OF_getpropint(ic->ic_node, "phandle", 0); 62 if (ic->ic_phandle == 0) 63 return; 64 65 LIST_FOREACH(tmp, &octeon_ic_list, ic_list) { 66 if (tmp->ic_phandle == ic->ic_phandle) { 67 printf("%s: node %d: duplicate phandle %d\n", 68 __func__, ic->ic_node, ic->ic_phandle); 69 return; 70 } 71 } 72 73 LIST_INSERT_HEAD(&octeon_ic_list, ic, ic_list); 74 } 75 76 void 77 octeon_intr_init(void) 78 { 79 octeon_ic->ic_init(); 80 } 81 82 /* 83 * Establish an interrupt handler called from the dispatcher. 84 * The interrupt function established should return zero if there was nothing 85 * to serve (no int) and non-zero when an interrupt was serviced. 86 */ 87 void * 88 octeon_intr_establish(int irq, int level, 89 int (*ih_fun)(void *), void *ih_arg, const char *ih_what) 90 { 91 struct intr_controller *ic = octeon_ic; 92 struct intr_handle *ih; 93 void *handler; 94 95 ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT); 96 if (ih == NULL) 97 return NULL; 98 99 handler = ic->ic_establish(irq, level, ih_fun, ih_arg, ih_what); 100 if (handler == NULL) { 101 free(ih, M_DEVBUF, sizeof(*ih)); 102 return NULL; 103 } 104 105 ih->ih_ic = ic; 106 ih->ih_ih = handler; 107 108 return ih; 109 } 110 111 void * 112 octeon_intr_establish_fdt(int node, int level, 113 int (*ih_fun)(void *), void *ih_arg, const char *ih_what) 114 { 115 return octeon_intr_establish_fdt_idx(node, 0, level, ih_fun, 116 ih_arg, ih_what); 117 } 118 119 void * 120 octeon_intr_establish_fdt_idx(int node, int idx, int level, 121 int (*ih_fun)(void *), void *ih_arg, const char *ih_what) 122 { 123 struct intr_controller *ic = NULL; 124 struct intr_handle *ih; 125 void *handler; 126 int phandle; 127 128 phandle = OF_getpropint(node, "interrupt-parent", 1); 129 if (phandle < 1) 130 return NULL; 131 132 LIST_FOREACH(ic, &octeon_ic_list, ic_list) { 133 if (ic->ic_phandle == phandle) 134 break; 135 } 136 if (ic == NULL) 137 return NULL; 138 139 ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT); 140 if (ih == NULL) 141 return NULL; 142 143 handler = ic->ic_establish_fdt_idx(ic->ic_cookie, node, idx, level, 144 ih_fun, ih_arg, ih_what); 145 if (handler == NULL) { 146 free(ih, M_DEVBUF, sizeof(*ih)); 147 return NULL; 148 } 149 150 ih->ih_ic = ic; 151 ih->ih_ih = handler; 152 153 return ih; 154 } 155 156 void 157 octeon_intr_disestablish(void *cookie) 158 { 159 struct intr_handle *ih = cookie; 160 struct intr_controller *ic = ih->ih_ic; 161 162 ic->ic_disestablish(ih->ih_ih); 163 free(ih, M_DEVBUF, sizeof(*ih)); 164 } 165 166 void 167 octeon_intr_disestablish_fdt(void *cookie) 168 { 169 octeon_intr_disestablish(cookie); 170 } 171 172 void 173 intr_barrier(void *cookie) 174 { 175 struct intr_handle *ih = cookie; 176 struct intr_controller *ic = ih->ih_ic; 177 178 ic->ic_intr_barrier(ih->ih_ih); 179 } 180 181 #ifdef MULTIPROCESSOR 182 /* 183 * Inter-processor interrupt control logic. 184 */ 185 186 int 187 hw_ipi_intr_establish(int (*func)(void *), u_long cpuid) 188 { 189 return octeon_ic->ic_ipi_establish(func, cpuid); 190 } 191 192 void 193 hw_ipi_intr_set(u_long cpuid) 194 { 195 octeon_ic->ic_ipi_set(cpuid); 196 } 197 198 void 199 hw_ipi_intr_clear(u_long cpuid) 200 { 201 octeon_ic->ic_ipi_clear(cpuid); 202 } 203 #endif /* MULTIPROCESSOR */ 204