Home | History | Annotate | Line # | Download | only in arm
      1 /*	$NetBSD: fiq.c,v 1.10 2020/02/24 12:08:08 rin 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 __KERNEL_RCSID(0, "$NetBSD: fiq.c,v 1.10 2020/02/24 12:08:08 rin Exp $");
     40 
     41 #include <sys/param.h>
     42 #include <sys/systm.h>
     43 
     44 #include <arm/cpufunc.h>
     45 #include <arm/fiq.h>
     46 
     47 #include <uvm/uvm_extern.h>
     48 
     49 TAILQ_HEAD(, fiqhandler) fiqhandler_stack =
     50     TAILQ_HEAD_INITIALIZER(fiqhandler_stack);
     51 
     52 extern char fiqvector[];
     53 extern char fiq_nullhandler[], fiq_nullhandler_end[];
     54 
     55 #define	IRQ_BIT		I32_bit
     56 #define	FIQ_BIT		F32_bit
     57 
     58 #ifndef ARM_HAS_VBAR
     59 /*
     60  * fiq_installhandler:
     61  *
     62  *	Actually install the FIQ handler down at the FIQ vector.
     63  *
     64  *	Note: If the FIQ is invoked via an extra layer of
     65  *	indirection, the actual FIQ code store lives in the
     66  *	data segment, so there is no need to manipulate
     67  *	the vector page's protection.
     68  */
     69 static void
     70 fiq_installhandler(void *func, size_t size)
     71 {
     72 #if !defined(__ARM_FIQ_INDIRECT)
     73 	vector_page_setprot(VM_PROT_READ|VM_PROT_WRITE);
     74 #endif
     75 
     76 	memcpy(fiqvector, func, size);
     77 
     78 #if !defined(__ARM_FIQ_INDIRECT)
     79 	vector_page_setprot(VM_PROT_READ);
     80 #endif
     81 	cpu_icache_sync_range((vaddr_t) fiqvector, size);
     82 }
     83 
     84 /*
     85  * fiq_claim:
     86  *
     87  *	Claim the FIQ vector.
     88  */
     89 int
     90 fiq_claim(struct fiqhandler *fh)
     91 {
     92 	struct fiqhandler *ofh;
     93 	u_int oldirqstate;
     94 	int error = 0;
     95 
     96 	if (fh->fh_size > 0x100)
     97 		return (EFBIG);
     98 
     99 	oldirqstate = disable_interrupts(FIQ_BIT);
    100 
    101 	if ((ofh = TAILQ_FIRST(&fiqhandler_stack)) != NULL) {
    102 		if ((ofh->fh_flags & FH_CANPUSH) == 0) {
    103 			error = EBUSY;
    104 			goto out;
    105 		}
    106 
    107 		/* Save the previous FIQ handler's registers. */
    108 		if (ofh->fh_regs != NULL)
    109 			fiq_getregs(ofh->fh_regs);
    110 	}
    111 
    112 	/* Set FIQ mode registers to ours. */
    113 	if (fh->fh_regs != NULL)
    114 		fiq_setregs(fh->fh_regs);
    115 
    116 	TAILQ_INSERT_HEAD(&fiqhandler_stack, fh, fh_list);
    117 
    118 	/* Now copy the actual handler into place. */
    119 	fiq_installhandler(fh->fh_func, fh->fh_size);
    120 
    121 	/* Make sure FIQs are enabled when we return. */
    122 	oldirqstate &= ~FIQ_BIT;
    123 
    124  out:
    125 	restore_interrupts(oldirqstate);
    126 	return (error);
    127 }
    128 
    129 /*
    130  * fiq_release:
    131  *
    132  *	Release the FIQ vector.
    133  */
    134 void
    135 fiq_release(struct fiqhandler *fh)
    136 {
    137 	u_int oldirqstate;
    138 	struct fiqhandler *ofh;
    139 
    140 	oldirqstate = disable_interrupts(FIQ_BIT);
    141 
    142 	/*
    143 	 * If we are the currently active FIQ handler, then we
    144 	 * need to save our registers and pop the next one back
    145 	 * into the vector.
    146 	 */
    147 	if (fh == TAILQ_FIRST(&fiqhandler_stack)) {
    148 		if (fh->fh_regs != NULL)
    149 			fiq_getregs(fh->fh_regs);
    150 		TAILQ_REMOVE(&fiqhandler_stack, fh, fh_list);
    151 		if ((ofh = TAILQ_FIRST(&fiqhandler_stack)) != NULL) {
    152 			if (ofh->fh_regs != NULL)
    153 				fiq_setregs(ofh->fh_regs);
    154 			fiq_installhandler(ofh->fh_func, ofh->fh_size);
    155 		}
    156 	} else
    157 		TAILQ_REMOVE(&fiqhandler_stack, fh, fh_list);
    158 
    159 	if (TAILQ_FIRST(&fiqhandler_stack) == NULL) {
    160 		/* Copy the NULL handler back down into the vector. */
    161 		fiq_installhandler(fiq_nullhandler,
    162 		    (size_t)(fiq_nullhandler_end - fiq_nullhandler));
    163 
    164 		/* Make sure FIQs are disabled when we return. */
    165 		oldirqstate |= FIQ_BIT;
    166 	}
    167 
    168 	oldirqstate &= ~FIQ_BIT;
    169 	restore_interrupts(oldirqstate);
    170 }
    171 #endif /* !ARM_HAS_VBAR */
    172