1 /* $NetBSD: intc.c,v 1.1 2001/10/16 15:38:38 uch Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by UCHIYAMA Yasushi. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include "debug_playstation2.h" 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 44 #include <playstation2/ee/eevar.h> 45 #include <playstation2/ee/intcvar.h> 46 #include <playstation2/ee/intcreg.h> 47 #include <playstation2/ee/gsvar.h> /* debug monitor */ 48 49 #include <playstation2/playstation2/interrupt.h> 50 51 #ifdef DEBUG 52 #define LEGAL_CHANNEL(x) ((x) >= 0 && (x) <= 15) 53 #define STATIC 54 #else 55 #define STATIC static 56 #endif 57 58 #define _INTC_NINTR 16 59 60 u_int32_t __intc_enabled_channel; 61 62 STATIC int __intc_initialized; 63 STATIC struct _ipl_dispatcher __intc_dispatcher[_INTC_NINTR]; 64 STATIC struct _ipl_holder __intc_ipl_holder[_IPL_N]; 65 66 STATIC SLIST_HEAD(, _ipl_dispatcher) __intc_dispatcher_head = 67 SLIST_HEAD_INITIALIZER(__intc_dispatcher_head); 68 69 void 70 intc_init() 71 { 72 int i; 73 74 if (__intc_initialized++) 75 return; 76 77 /* disable all channel */ 78 for (i = 0; i < _INTC_NINTR; i++) 79 intc_intr_disable(i); 80 81 /* clear interrupts */ 82 _reg_write_4(I_STAT_REG, _reg_read_4(I_STAT_REG)); 83 84 for (i = 0; i < _IPL_N; i++) 85 __intc_ipl_holder[i].mask = 0xffffffff; 86 } 87 88 int 89 intc_intr(u_int32_t mask) 90 { 91 struct _ipl_dispatcher *dispatcher; 92 u_int32_t r, dispatch, pending; 93 94 r = _reg_read_4(I_STAT_REG); 95 dispatch = r & ~mask & __intc_enabled_channel; 96 pending = r & mask & __intc_enabled_channel; 97 98 #if 0 99 __gsfb_print(1, 100 "INTC stat=%08x, mask=%08x, pend=%08x, disp=%08x enable=%08x\n", 101 r, mask, pending, dispatch, __intc_enabled_channel); 102 #endif 103 if (dispatch == 0) 104 return (pending == 0 ? 1 : 0); 105 106 /* clear interrupt */ 107 _reg_write_4(I_STAT_REG, dispatch); 108 109 /* dispatch interrupt handler */ 110 SLIST_FOREACH(dispatcher, &__intc_dispatcher_head, link) { 111 if (dispatcher->bit & dispatch) { 112 KDASSERT(dispatcher->func); 113 (*dispatcher->func)(dispatcher->arg); 114 dispatch &= ~dispatcher->bit; 115 } 116 } 117 118 /* disable spurious interrupt source */ 119 if (dispatch) { 120 int i, bit; 121 for (i = 0, bit = 1; i < _INTC_NINTR; i++, bit <<= 1) { 122 if (bit & dispatch) { 123 intc_intr_disable(i); 124 printf("%s: spurious interrupt %d disabled.\n", 125 __FUNCTION__, i); 126 } 127 } 128 } 129 130 return (pending == 0 ? 1 : 0); 131 } 132 133 void 134 intc_intr_enable(enum intc_channel ch) 135 { 136 u_int32_t mask; 137 138 KDASSERT(LEGAL_CHANNEL(ch)); 139 mask = 1 << ch; 140 _reg_write_4(I_MASK_REG, (_reg_read_4(I_MASK_REG) & mask) ^ mask); 141 } 142 143 void 144 intc_intr_disable(enum intc_channel ch) 145 { 146 147 KDASSERT(LEGAL_CHANNEL(ch)); 148 _reg_write_4(I_MASK_REG, _reg_read_4(I_MASK_REG) & (1 << ch)); 149 } 150 151 void 152 intc_update_mask(u_int32_t mask) 153 { 154 u_int32_t cur_mask; 155 156 cur_mask = _reg_read_4(I_MASK_REG); 157 158 _reg_write_4(I_MASK_REG, ((cur_mask ^ ~mask) | (cur_mask & mask)) & 159 __intc_enabled_channel); 160 } 161 162 void * 163 intc_intr_establish(enum intc_channel ch, int ipl, int (*func)(void *), 164 void *arg) 165 { 166 struct _ipl_dispatcher *dispatcher = &__intc_dispatcher[ch]; 167 struct _ipl_dispatcher *d; 168 u_int32_t bit; 169 int i, s; 170 171 KDASSERT(dispatcher->func == NULL); 172 173 s = _intr_suspend(); 174 dispatcher->func = func; 175 dispatcher->arg = arg; 176 dispatcher->ipl = ipl; 177 dispatcher->channel = ch; 178 dispatcher->bit = bit = (1 << ch); 179 180 for (i = 0; i < _IPL_N; i++) 181 if (i < ipl) 182 __intc_ipl_holder[i].mask &= ~bit; 183 else 184 __intc_ipl_holder[i].mask |= bit; 185 186 /* insert queue IPL order */ 187 if (SLIST_EMPTY(&__intc_dispatcher_head)) { 188 SLIST_INSERT_HEAD(&__intc_dispatcher_head, dispatcher, link); 189 } else { 190 SLIST_FOREACH(d, &__intc_dispatcher_head, link) { 191 if (SLIST_NEXT(d, link) == 0 || 192 SLIST_NEXT(d, link)->ipl < ipl) { 193 SLIST_INSERT_AFTER(d, dispatcher, link); 194 break; 195 } 196 } 197 } 198 199 md_ipl_register(IPL_INTC, __intc_ipl_holder); 200 201 intc_intr_enable(ch); 202 __intc_enabled_channel |= bit; 203 204 _intr_resume(s); 205 206 return ((void *)ch); 207 } 208 209 void 210 intc_intr_disestablish(void *handle) 211 { 212 int ch = (int)(handle); 213 struct _ipl_dispatcher *dispatcher = &__intc_dispatcher[ch]; 214 u_int32_t bit; 215 int i, s; 216 217 s = _intr_suspend(); 218 219 intc_intr_disable(ch); 220 dispatcher->func = NULL; 221 222 SLIST_REMOVE(&__intc_dispatcher_head, dispatcher, 223 _ipl_dispatcher, link); 224 225 bit = dispatcher->bit; 226 for (i = 0; i < _IPL_N; i++) 227 __intc_ipl_holder[i].mask |= bit; 228 229 md_ipl_register(IPL_INTC, __intc_ipl_holder); 230 __intc_enabled_channel &= ~bit; 231 232 _intr_resume(s); 233 } 234 235