1 /* $OpenBSD: octeon_intr.c,v 1.22 2017/06/18 13:58:44 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 return octeon_ic->ic_establish(irq, level, ih_fun, ih_arg, ih_what); 92 } 93 94 void * 95 octeon_intr_establish_fdt(int node, int level, 96 int (*ih_fun)(void *), void *ih_arg, const char *ih_what) 97 { 98 return octeon_intr_establish_fdt_idx(node, 0, level, ih_fun, 99 ih_arg, ih_what); 100 } 101 102 void * 103 octeon_intr_establish_fdt_idx(int node, int idx, int level, 104 int (*ih_fun)(void *), void *ih_arg, const char *ih_what) 105 { 106 struct intr_controller *ic = NULL; 107 struct intr_handle *ih; 108 void *handler; 109 int phandle; 110 111 phandle = OF_getpropint(node, "interrupt-parent", 1); 112 if (phandle < 1) 113 return NULL; 114 115 LIST_FOREACH(ic, &octeon_ic_list, ic_list) { 116 if (ic->ic_phandle == phandle) 117 break; 118 } 119 if (ic == NULL) 120 return NULL; 121 122 ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT); 123 if (ih == NULL) 124 return NULL; 125 126 handler = ic->ic_establish_fdt_idx(ic->ic_cookie, node, idx, level, 127 ih_fun, ih_arg, ih_what); 128 if (handler == NULL) { 129 free(ih, M_DEVBUF, sizeof(*ih)); 130 return NULL; 131 } 132 133 ih->ih_ic = ic; 134 ih->ih_ih = handler; 135 return ih; 136 } 137 138 void 139 octeon_intr_disestablish(void *cookie) 140 { 141 octeon_ic->ic_disestablish(cookie); 142 } 143 144 void 145 octeon_intr_disestablish_fdt(void *cookie) 146 { 147 struct intr_handle *ih = cookie; 148 struct intr_controller *ic = ih->ih_ic; 149 150 ic->ic_disestablish(ih->ih_ih); 151 free(ih, M_DEVBUF, sizeof(*ih)); 152 } 153 154 #ifdef MULTIPROCESSOR 155 /* 156 * Inter-processor interrupt control logic. 157 */ 158 159 int 160 hw_ipi_intr_establish(int (*func)(void *), u_long cpuid) 161 { 162 return octeon_ic->ic_ipi_establish(func, cpuid); 163 } 164 165 void 166 hw_ipi_intr_set(u_long cpuid) 167 { 168 octeon_ic->ic_ipi_set(cpuid); 169 } 170 171 void 172 hw_ipi_intr_clear(u_long cpuid) 173 { 174 octeon_ic->ic_ipi_clear(cpuid); 175 } 176 #endif /* MULTIPROCESSOR */ 177