/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * Interrupt Vector Table Configuration */ #include #include #include #include #include #include /* * fill in an interrupt vector entry */ #define fill_intr(a, b, c, d, e) \ a->iv_pil = b; a->iv_pending = 0; \ a->iv_arg = d; a->iv_handler = c; a->iv_payload_buf = e; /* * create a null interrupt handler entry used for returned values * only - never on intr_vector[] */ #define nullify_intr(v) fill_intr(v, 0, NULL, NULL, NULL) /* * replace an intr_vector[] entry with a default set of values * this is done instead of nulling the entry, so the handler and * pil are always valid for the assembler code */ #define empty_intr(v) fill_intr((v), PIL_MAX, nohandler, \ (void *)(v), NULL) /* * test whether an intr_vector[] entry points to our default handler */ #define intr_is_empty(v) ((v)->iv_handler == nohandler) extern uint_t swinum_base; extern uint_t maxswinum; extern kmutex_t soft_iv_lock; int ignore_invalid_vecintr = 0; uint64_t invalid_vecintr_count = 0; /* * default (non-)handler for otherwise unhandled interrupts */ uint_t nohandler(caddr_t ivptr) { if (!ignore_invalid_vecintr) { ASSERT((struct intr_vector *)ivptr - intr_vector < MAXIVNUM); return (DDI_INTR_UNCLAIMED); } else { invalid_vecintr_count++; return (DDI_INTR_CLAIMED); } } /* * initialization - fill the entire table with default values */ void init_ivintr(void) { struct intr_vector *inump; int i; for (inump = intr_vector, i = 0; i <= MAXIVNUM; ++inump, ++i) { empty_intr(inump); } } /* * add_ivintr() - add an interrupt handler to the system * This routine is not protected by the lock; it's the caller's * responsibility to make sure _INR.INT_EN = 0 * and _ISM != PENDING before the routine is called. */ int add_ivintr(uint_t inum, uint_t pil, intrfunc intr_handler, caddr_t intr_arg, caddr_t intr_payload) { struct intr_vector *inump; if (inum >= MAXIVNUM || pil > PIL_MAX) return (EINVAL); ASSERT((uintptr_t)intr_handler > KERNELBASE); /* Make sure the payload buffer address is 64 bit aligned */ VERIFY(((uint64_t)intr_payload & 0x7) == 0); inump = &intr_vector[inum]; if (inump->iv_handler != nohandler) return (EINVAL); fill_intr(inump, (ushort_t)pil, intr_handler, intr_arg, intr_payload); return (0); } /* * rem_ivintr() - remove an interrupt handler from intr_vector[] * This routine is not protected by the lock; it's the caller's * responsibility to make sure _INR.INT_EN = 0 * and _ISM != PENDING before the routine is called. */ void rem_ivintr(uint_t inum, struct intr_vector *iv_return) { struct intr_vector *inump; ASSERT(inum != NULL && inum < MAXIVNUM); inump = &intr_vector[inum]; if (iv_return) { if (intr_is_empty(inump)) { nullify_intr(iv_return); } else { /* * the caller requires the current entry to be * returned */ fill_intr(iv_return, inump->iv_pil, inump->iv_handler, inump->iv_arg, inump->iv_payload_buf); } } /* * empty the current entry */ empty_intr(inump); } /* * add_softintr() - add a software interrupt handler to the system */ uint_t add_softintr(uint_t pil, softintrfunc intr_handler, caddr_t intr_arg) { struct intr_vector *inump; register uint_t i; mutex_enter(&soft_iv_lock); for (i = swinum_base; i < maxswinum; i++) { inump = &intr_vector[i]; if (intr_is_empty(inump)) break; } if (!intr_is_empty(inump)) { cmn_err(CE_PANIC, "add_softintr: exceeded %d handlers", maxswinum - swinum_base); } VERIFY(add_ivintr(i, pil, (intrfunc)intr_handler, intr_arg, NULL) == 0); mutex_exit(&soft_iv_lock); return (i); } /* * rem_softintr() - remove a software interrupt handler from the system */ void rem_softintr(uint_t inum) { ASSERT(swinum_base <= inum && inum < MAXIVNUM); mutex_enter(&soft_iv_lock); rem_ivintr(inum, NULL); mutex_exit(&soft_iv_lock); } int update_softint_arg2(uint_t intr_id, caddr_t arg2) { struct intr_vector *inump = &intr_vector[intr_id]; if (inump->iv_pending) return (DDI_EPENDING); inump->iv_softint_arg2 = arg2; return (DDI_SUCCESS); } int update_softint_pri(uint_t intr_id, int pri) { struct intr_vector *inump = &intr_vector[intr_id]; mutex_enter(&soft_iv_lock); inump->iv_pil = pri; mutex_exit(&soft_iv_lock); return (DDI_SUCCESS); }