1 /* $NetBSD: fiq.c,v 1.5 2002/04/03 23:33:27 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 2001, 2002 Wasabi Systems, Inc. 5 * All rights reserved. 6 * 7 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the NetBSD Project by 20 * Wasabi Systems, Inc. 21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 22 * or promote products derived from this software without specific prior 23 * written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include <sys/cdefs.h> 39 __FBSDID("$FreeBSD$"); 40 41 #include <sys/param.h> 42 #include <sys/systm.h> 43 44 #include <machine/cpufunc.h> 45 #include <machine/fiq.h> 46 #include <vm/vm.h> 47 #include <machine/pcb.h> 48 #include <vm/pmap.h> 49 #include <machine/cpu.h> 50 51 TAILQ_HEAD(, fiqhandler) fiqhandler_stack = 52 TAILQ_HEAD_INITIALIZER(fiqhandler_stack); 53 54 extern char fiqvector[]; 55 extern char fiq_nullhandler[], fiq_nullhandler_end[]; 56 57 #define IRQ_BIT I32_bit 58 #define FIQ_BIT F32_bit 59 60 /* 61 * fiq_installhandler: 62 * 63 * Actually install the FIQ handler down at the FIQ vector. 64 * 65 * Note: If the FIQ is invoked via an extra layer of 66 * indirection, the actual FIQ code store lives in the 67 * data segment, so there is no need to manipulate 68 * the vector page's protection. 69 */ 70 static void 71 fiq_installhandler(void *func, size_t size) 72 { 73 #if !defined(__ARM_FIQ_INDIRECT) 74 vector_page_setprot(VM_PROT_READ|VM_PROT_WRITE); 75 #endif 76 77 memcpy(vector_page + fiqvector, func, size); 78 79 #if !defined(__ARM_FIQ_INDIRECT) 80 vector_page_setprot(VM_PROT_READ); 81 cpu_icache_sync_range((vm_offset_t) fiqvector, size); 82 #endif 83 } 84 85 /* 86 * fiq_claim: 87 * 88 * Claim the FIQ vector. 89 */ 90 int 91 fiq_claim(struct fiqhandler *fh) 92 { 93 struct fiqhandler *ofh; 94 u_int oldirqstate; 95 int error = 0; 96 97 if (fh->fh_size > 0x100) 98 return (EFBIG); 99 100 oldirqstate = disable_interrupts(FIQ_BIT); 101 102 if ((ofh = TAILQ_FIRST(&fiqhandler_stack)) != NULL) { 103 if ((ofh->fh_flags & FH_CANPUSH) == 0) { 104 error = EBUSY; 105 goto out; 106 } 107 108 /* Save the previous FIQ handler's registers. */ 109 if (ofh->fh_regs != NULL) 110 fiq_getregs(ofh->fh_regs); 111 } 112 113 /* Set FIQ mode registers to ours. */ 114 if (fh->fh_regs != NULL) 115 fiq_setregs(fh->fh_regs); 116 117 TAILQ_INSERT_HEAD(&fiqhandler_stack, fh, fh_list); 118 119 /* Now copy the actual handler into place. */ 120 fiq_installhandler(fh->fh_func, fh->fh_size); 121 122 /* Make sure FIQs are enabled when we return. */ 123 oldirqstate &= ~FIQ_BIT; 124 125 out: 126 restore_interrupts(oldirqstate); 127 return (error); 128 } 129 130 /* 131 * fiq_release: 132 * 133 * Release the FIQ vector. 134 */ 135 void 136 fiq_release(struct fiqhandler *fh) 137 { 138 u_int oldirqstate; 139 struct fiqhandler *ofh; 140 141 oldirqstate = disable_interrupts(FIQ_BIT); 142 143 /* 144 * If we are the currently active FIQ handler, then we 145 * need to save our registers and pop the next one back 146 * into the vector. 147 */ 148 if (fh == TAILQ_FIRST(&fiqhandler_stack)) { 149 if (fh->fh_regs != NULL) 150 fiq_getregs(fh->fh_regs); 151 TAILQ_REMOVE(&fiqhandler_stack, fh, fh_list); 152 if ((ofh = TAILQ_FIRST(&fiqhandler_stack)) != NULL) { 153 if (ofh->fh_regs != NULL) 154 fiq_setregs(ofh->fh_regs); 155 fiq_installhandler(ofh->fh_func, ofh->fh_size); 156 } 157 } else 158 TAILQ_REMOVE(&fiqhandler_stack, fh, fh_list); 159 160 if (TAILQ_FIRST(&fiqhandler_stack) == NULL) { 161 /* Copy the NULL handler back down into the vector. */ 162 fiq_installhandler(fiq_nullhandler, 163 (size_t)(fiq_nullhandler_end - fiq_nullhandler)); 164 165 /* Make sure FIQs are disabled when we return. */ 166 oldirqstate |= FIQ_BIT; 167 } 168 169 restore_interrupts(oldirqstate); 170 } 171