17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*b0fc0e77Sgovinda * Common Development and Distribution License (the "License"). 6*b0fc0e77Sgovinda * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*b0fc0e77Sgovinda * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * Interrupt Vector Table Configuration 307c478bd9Sstevel@tonic-gate */ 317c478bd9Sstevel@tonic-gate 32*b0fc0e77Sgovinda #include <sys/types.h> 337c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h> 347c478bd9Sstevel@tonic-gate #include <sys/ivintr.h> 357c478bd9Sstevel@tonic-gate #include <sys/intreg.h> 367c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 377c478bd9Sstevel@tonic-gate #include <sys/privregs.h> 387c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate /* 41*b0fc0e77Sgovinda * Allocate an Interrupt Vector Table and some interrupt vector data structures 42*b0fc0e77Sgovinda * for the reserved pool as part of the startup code. First try to allocate an 43*b0fc0e77Sgovinda * interrupt vector data structure from the reserved pool, otherwise allocate it 44*b0fc0e77Sgovinda * using kmem cache method. 457c478bd9Sstevel@tonic-gate */ 46*b0fc0e77Sgovinda static kmutex_t intr_vec_mutex; /* Protect interrupt vector table */ 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate /* 49*b0fc0e77Sgovinda * Global softint linked list - used by softint mdb dcmd. 507c478bd9Sstevel@tonic-gate */ 51*b0fc0e77Sgovinda static kmutex_t softint_mutex; /* Protect global softint linked list */ 52*b0fc0e77Sgovinda intr_vec_t *softint_list = NULL; 53*b0fc0e77Sgovinda 54*b0fc0e77Sgovinda /* Reserved pool for interrupt allocation */ 55*b0fc0e77Sgovinda intr_vec_t *intr_vec_pool = NULL; /* For HW and single target SW intrs */ 56*b0fc0e77Sgovinda intr_vecx_t *intr_vecx_pool = NULL; /* For multi target SW intrs */ 57*b0fc0e77Sgovinda 58*b0fc0e77Sgovinda /* Kmem cache handle for interrupt allocation */ 59*b0fc0e77Sgovinda kmem_cache_t *intr_vec_cache = NULL; /* For HW and single target SW intrs */ 607c478bd9Sstevel@tonic-gate 617c478bd9Sstevel@tonic-gate /* 62*b0fc0e77Sgovinda * init_ivintr() - Initialize an Interrupt Vector Table. 637c478bd9Sstevel@tonic-gate */ 647c478bd9Sstevel@tonic-gate void 65*b0fc0e77Sgovinda init_ivintr() 667c478bd9Sstevel@tonic-gate { 67*b0fc0e77Sgovinda mutex_init(&intr_vec_mutex, NULL, MUTEX_DRIVER, NULL); 68*b0fc0e77Sgovinda mutex_init(&softint_mutex, NULL, MUTEX_DRIVER, NULL); 697c478bd9Sstevel@tonic-gate 70*b0fc0e77Sgovinda /* 71*b0fc0e77Sgovinda * Initialize the reserved interrupt vector data structure pools 72*b0fc0e77Sgovinda * used for hardware and software interrupts. 73*b0fc0e77Sgovinda */ 74*b0fc0e77Sgovinda intr_vec_pool = (intr_vec_t *)((caddr_t)intr_vec_table + 75*b0fc0e77Sgovinda (MAXIVNUM * sizeof (intr_vec_t *))); 76*b0fc0e77Sgovinda intr_vecx_pool = (intr_vecx_t *)((caddr_t)intr_vec_pool + 77*b0fc0e77Sgovinda (MAX_RSVD_IV * sizeof (intr_vec_t))); 78*b0fc0e77Sgovinda 79*b0fc0e77Sgovinda bzero(intr_vec_table, MAXIVNUM * sizeof (intr_vec_t *)); 80*b0fc0e77Sgovinda bzero(intr_vec_pool, MAX_RSVD_IV * sizeof (intr_vec_t)); 81*b0fc0e77Sgovinda bzero(intr_vecx_pool, MAX_RSVD_IVX * sizeof (intr_vecx_t)); 82*b0fc0e77Sgovinda } 83*b0fc0e77Sgovinda 84*b0fc0e77Sgovinda /* 85*b0fc0e77Sgovinda * fini_ivintr() - Uninitialize an Interrupt Vector Table. 86*b0fc0e77Sgovinda */ 87*b0fc0e77Sgovinda void 88*b0fc0e77Sgovinda fini_ivintr() 89*b0fc0e77Sgovinda { 90*b0fc0e77Sgovinda if (intr_vec_cache) 91*b0fc0e77Sgovinda kmem_cache_destroy(intr_vec_cache); 92*b0fc0e77Sgovinda 93*b0fc0e77Sgovinda mutex_destroy(&intr_vec_mutex); 94*b0fc0e77Sgovinda mutex_destroy(&softint_mutex); 95*b0fc0e77Sgovinda } 96*b0fc0e77Sgovinda 97*b0fc0e77Sgovinda /* 98*b0fc0e77Sgovinda * iv_alloc() - Allocate an interrupt vector data structure. 99*b0fc0e77Sgovinda * 100*b0fc0e77Sgovinda * This function allocates an interrupt vector data structure for hardware 101*b0fc0e77Sgovinda * and single or multi target software interrupts either from the reserved 102*b0fc0e77Sgovinda * pool or using kmem cache method. 103*b0fc0e77Sgovinda */ 104*b0fc0e77Sgovinda static intr_vec_t * 105*b0fc0e77Sgovinda iv_alloc(softint_type_t type) 106*b0fc0e77Sgovinda { 107*b0fc0e77Sgovinda intr_vec_t *iv_p; 108*b0fc0e77Sgovinda int i, count; 109*b0fc0e77Sgovinda 110*b0fc0e77Sgovinda count = (type == SOFTINT_MT) ? MAX_RSVD_IVX : MAX_RSVD_IV; 111*b0fc0e77Sgovinda 112*b0fc0e77Sgovinda /* 113*b0fc0e77Sgovinda * First try to allocate an interrupt vector data structure from the 114*b0fc0e77Sgovinda * reserved pool, otherwise allocate it using kmem_cache_alloc(). 115*b0fc0e77Sgovinda */ 116*b0fc0e77Sgovinda for (i = 0; i < count; i++) { 117*b0fc0e77Sgovinda iv_p = (type == SOFTINT_MT) ? 118*b0fc0e77Sgovinda (intr_vec_t *)&intr_vecx_pool[i] : &intr_vec_pool[i]; 119*b0fc0e77Sgovinda 120*b0fc0e77Sgovinda if (iv_p->iv_pil == 0) 121*b0fc0e77Sgovinda break; 122*b0fc0e77Sgovinda } 123*b0fc0e77Sgovinda 124*b0fc0e77Sgovinda if (i < count) 125*b0fc0e77Sgovinda return (iv_p); 126*b0fc0e77Sgovinda 127*b0fc0e77Sgovinda if (type == SOFTINT_MT) 128*b0fc0e77Sgovinda cmn_err(CE_PANIC, "iv_alloc: exceeded number of multi " 129*b0fc0e77Sgovinda "target software interrupts, %d", MAX_RSVD_IVX); 130*b0fc0e77Sgovinda 131*b0fc0e77Sgovinda /* 132*b0fc0e77Sgovinda * If the interrupt vector data structure reserved pool is already 133*b0fc0e77Sgovinda * exhausted, then allocate an interrupt vector data structure using 134*b0fc0e77Sgovinda * kmem_cache_alloc(), but only for the hardware and single software 135*b0fc0e77Sgovinda * interrupts. Create a kmem cache for the interrupt allocation, 136*b0fc0e77Sgovinda * if it is not already available. 137*b0fc0e77Sgovinda */ 138*b0fc0e77Sgovinda if (intr_vec_cache == NULL) 139*b0fc0e77Sgovinda intr_vec_cache = kmem_cache_create("intr_vec_cache", 140*b0fc0e77Sgovinda sizeof (intr_vec_t), 64, NULL, NULL, NULL, NULL, NULL, 0); 141*b0fc0e77Sgovinda 142*b0fc0e77Sgovinda iv_p = kmem_cache_alloc(intr_vec_cache, KM_SLEEP); 143*b0fc0e77Sgovinda bzero(iv_p, sizeof (intr_vec_t)); 144*b0fc0e77Sgovinda 145*b0fc0e77Sgovinda iv_p->iv_flags = IV_CACHE_ALLOC; 146*b0fc0e77Sgovinda return (iv_p); 147*b0fc0e77Sgovinda } 148*b0fc0e77Sgovinda 149*b0fc0e77Sgovinda /* 150*b0fc0e77Sgovinda * iv_free() - Free an interrupt vector data structure. 151*b0fc0e77Sgovinda */ 152*b0fc0e77Sgovinda static void 153*b0fc0e77Sgovinda iv_free(intr_vec_t *iv_p) 154*b0fc0e77Sgovinda { 155*b0fc0e77Sgovinda if (iv_p->iv_flags & IV_CACHE_ALLOC) { 156*b0fc0e77Sgovinda ASSERT(!(iv_p->iv_flags & IV_SOFTINT_MT)); 157*b0fc0e77Sgovinda kmem_cache_free(intr_vec_cache, iv_p); 158*b0fc0e77Sgovinda } else { 159*b0fc0e77Sgovinda (iv_p->iv_flags & IV_SOFTINT_MT) ? 160*b0fc0e77Sgovinda bzero(iv_p, sizeof (intr_vecx_t)) : 161*b0fc0e77Sgovinda bzero(iv_p, sizeof (intr_vec_t)); 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate } 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate /* 166*b0fc0e77Sgovinda * add_ivintr() - Add an interrupt handler to the system 1677c478bd9Sstevel@tonic-gate */ 1687c478bd9Sstevel@tonic-gate int 1697c478bd9Sstevel@tonic-gate add_ivintr(uint_t inum, uint_t pil, intrfunc intr_handler, 170*b0fc0e77Sgovinda caddr_t intr_arg1, caddr_t intr_arg2, caddr_t intr_payload) 1717c478bd9Sstevel@tonic-gate { 172*b0fc0e77Sgovinda intr_vec_t *iv_p, *new_iv_p; 1737c478bd9Sstevel@tonic-gate 1747c478bd9Sstevel@tonic-gate if (inum >= MAXIVNUM || pil > PIL_MAX) 1757c478bd9Sstevel@tonic-gate return (EINVAL); 1767c478bd9Sstevel@tonic-gate 1777c478bd9Sstevel@tonic-gate ASSERT((uintptr_t)intr_handler > KERNELBASE); 178*b0fc0e77Sgovinda 1797c478bd9Sstevel@tonic-gate /* Make sure the payload buffer address is 64 bit aligned */ 1807c478bd9Sstevel@tonic-gate VERIFY(((uint64_t)intr_payload & 0x7) == 0); 1817c478bd9Sstevel@tonic-gate 182*b0fc0e77Sgovinda new_iv_p = iv_alloc(SOFTINT_ST); 183*b0fc0e77Sgovinda mutex_enter(&intr_vec_mutex); 1847c478bd9Sstevel@tonic-gate 185*b0fc0e77Sgovinda for (iv_p = (intr_vec_t *)intr_vec_table[inum]; 186*b0fc0e77Sgovinda iv_p; iv_p = iv_p->iv_vec_next) { 187*b0fc0e77Sgovinda if (iv_p->iv_pil == pil) { 188*b0fc0e77Sgovinda mutex_exit(&intr_vec_mutex); 189*b0fc0e77Sgovinda iv_free(new_iv_p); 1907c478bd9Sstevel@tonic-gate return (EINVAL); 191*b0fc0e77Sgovinda } 192*b0fc0e77Sgovinda } 1937c478bd9Sstevel@tonic-gate 194*b0fc0e77Sgovinda ASSERT(iv_p == NULL); 195*b0fc0e77Sgovinda 196*b0fc0e77Sgovinda new_iv_p->iv_handler = intr_handler; 197*b0fc0e77Sgovinda new_iv_p->iv_arg1 = intr_arg1; 198*b0fc0e77Sgovinda new_iv_p->iv_arg2 = intr_arg2; 199*b0fc0e77Sgovinda new_iv_p->iv_payload_buf = intr_payload; 200*b0fc0e77Sgovinda new_iv_p->iv_pil = (ushort_t)pil; 201*b0fc0e77Sgovinda new_iv_p->iv_inum = inum; 202*b0fc0e77Sgovinda 203*b0fc0e77Sgovinda new_iv_p->iv_vec_next = (intr_vec_t *)intr_vec_table[inum]; 204*b0fc0e77Sgovinda intr_vec_table[inum] = (uint64_t)new_iv_p; 205*b0fc0e77Sgovinda 206*b0fc0e77Sgovinda mutex_exit(&intr_vec_mutex); 2077c478bd9Sstevel@tonic-gate return (0); 2087c478bd9Sstevel@tonic-gate } 2097c478bd9Sstevel@tonic-gate 2107c478bd9Sstevel@tonic-gate /* 211*b0fc0e77Sgovinda * rem_ivintr() - Remove an interrupt handler from the system 2127c478bd9Sstevel@tonic-gate */ 213*b0fc0e77Sgovinda int 214*b0fc0e77Sgovinda rem_ivintr(uint_t inum, uint_t pil) 2157c478bd9Sstevel@tonic-gate { 216*b0fc0e77Sgovinda intr_vec_t *iv_p, *prev_iv_p; 2177c478bd9Sstevel@tonic-gate 218*b0fc0e77Sgovinda if (inum >= MAXIVNUM || pil > PIL_MAX) 219*b0fc0e77Sgovinda return (EINVAL); 2207c478bd9Sstevel@tonic-gate 221*b0fc0e77Sgovinda mutex_enter(&intr_vec_mutex); 2227c478bd9Sstevel@tonic-gate 223*b0fc0e77Sgovinda for (iv_p = prev_iv_p = (intr_vec_t *)intr_vec_table[inum]; 224*b0fc0e77Sgovinda iv_p; prev_iv_p = iv_p, iv_p = iv_p->iv_vec_next) 225*b0fc0e77Sgovinda if (iv_p->iv_pil == pil) 226*b0fc0e77Sgovinda break; 227*b0fc0e77Sgovinda 228*b0fc0e77Sgovinda if (iv_p == NULL) { 229*b0fc0e77Sgovinda mutex_exit(&intr_vec_mutex); 230*b0fc0e77Sgovinda return (EIO); 2317c478bd9Sstevel@tonic-gate } 2327c478bd9Sstevel@tonic-gate 233*b0fc0e77Sgovinda ASSERT(iv_p->iv_pil_next == NULL); 234*b0fc0e77Sgovinda 235*b0fc0e77Sgovinda if (prev_iv_p == iv_p) 236*b0fc0e77Sgovinda intr_vec_table[inum] = (uint64_t)iv_p->iv_vec_next; 237*b0fc0e77Sgovinda else 238*b0fc0e77Sgovinda prev_iv_p->iv_vec_next = iv_p->iv_vec_next; 239*b0fc0e77Sgovinda 240*b0fc0e77Sgovinda mutex_exit(&intr_vec_mutex); 241*b0fc0e77Sgovinda 242*b0fc0e77Sgovinda iv_free(iv_p); 243*b0fc0e77Sgovinda return (0); 2447c478bd9Sstevel@tonic-gate } 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate /* 2477c478bd9Sstevel@tonic-gate * add_softintr() - add a software interrupt handler to the system 2487c478bd9Sstevel@tonic-gate */ 249*b0fc0e77Sgovinda uint64_t 250*b0fc0e77Sgovinda add_softintr(uint_t pil, softintrfunc intr_handler, caddr_t intr_arg1, 251*b0fc0e77Sgovinda softint_type_t type) 2527c478bd9Sstevel@tonic-gate { 253*b0fc0e77Sgovinda intr_vec_t *iv_p; 2547c478bd9Sstevel@tonic-gate 255*b0fc0e77Sgovinda if (pil > PIL_MAX) 256*b0fc0e77Sgovinda return (NULL); 2577c478bd9Sstevel@tonic-gate 258*b0fc0e77Sgovinda iv_p = iv_alloc(type); 2597c478bd9Sstevel@tonic-gate 260*b0fc0e77Sgovinda iv_p->iv_handler = (intrfunc)intr_handler; 261*b0fc0e77Sgovinda iv_p->iv_arg1 = intr_arg1; 262*b0fc0e77Sgovinda iv_p->iv_pil = (ushort_t)pil; 263*b0fc0e77Sgovinda if (type == SOFTINT_MT) 264*b0fc0e77Sgovinda iv_p->iv_flags |= IV_SOFTINT_MT; 2657c478bd9Sstevel@tonic-gate 266*b0fc0e77Sgovinda mutex_enter(&softint_mutex); 267*b0fc0e77Sgovinda if (softint_list) 268*b0fc0e77Sgovinda iv_p->iv_vec_next = softint_list; 269*b0fc0e77Sgovinda softint_list = iv_p; 270*b0fc0e77Sgovinda mutex_exit(&softint_mutex); 2717c478bd9Sstevel@tonic-gate 272*b0fc0e77Sgovinda return ((uint64_t)iv_p); 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate /* 2767c478bd9Sstevel@tonic-gate * rem_softintr() - remove a software interrupt handler from the system 2777c478bd9Sstevel@tonic-gate */ 278*b0fc0e77Sgovinda int 279*b0fc0e77Sgovinda rem_softintr(uint64_t softint_id) 2807c478bd9Sstevel@tonic-gate { 281*b0fc0e77Sgovinda intr_vec_t *iv_p = (intr_vec_t *)softint_id; 2827c478bd9Sstevel@tonic-gate 283*b0fc0e77Sgovinda ASSERT(iv_p != NULL); 284*b0fc0e77Sgovinda 285*b0fc0e77Sgovinda if (iv_p->iv_flags & IV_SOFTINT_PEND) 286*b0fc0e77Sgovinda return (EIO); 287*b0fc0e77Sgovinda 288*b0fc0e77Sgovinda ASSERT(iv_p->iv_pil_next == NULL); 289*b0fc0e77Sgovinda 290*b0fc0e77Sgovinda mutex_enter(&softint_mutex); 291*b0fc0e77Sgovinda if (softint_list == iv_p) { 292*b0fc0e77Sgovinda softint_list = iv_p->iv_vec_next; 293*b0fc0e77Sgovinda } else { 294*b0fc0e77Sgovinda intr_vec_t *list = softint_list; 295*b0fc0e77Sgovinda 296*b0fc0e77Sgovinda while (list && (list->iv_vec_next != iv_p)) 297*b0fc0e77Sgovinda list = list->iv_vec_next; 298*b0fc0e77Sgovinda 299*b0fc0e77Sgovinda list->iv_vec_next = iv_p->iv_vec_next; 300*b0fc0e77Sgovinda } 301*b0fc0e77Sgovinda mutex_exit(&softint_mutex); 302*b0fc0e77Sgovinda 303*b0fc0e77Sgovinda iv_free(iv_p); 304*b0fc0e77Sgovinda return (0); 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate 307*b0fc0e77Sgovinda /* 308*b0fc0e77Sgovinda * update_softint_arg2() - Update softint arg2. 309*b0fc0e77Sgovinda * 310*b0fc0e77Sgovinda * NOTE: Do not grab any mutex in this function since it may get called 311*b0fc0e77Sgovinda * from the high-level interrupt context. 312*b0fc0e77Sgovinda */ 3137c478bd9Sstevel@tonic-gate int 314*b0fc0e77Sgovinda update_softint_arg2(uint64_t softint_id, caddr_t intr_arg2) 3157c478bd9Sstevel@tonic-gate { 316*b0fc0e77Sgovinda intr_vec_t *iv_p = (intr_vec_t *)softint_id; 3177c478bd9Sstevel@tonic-gate 318*b0fc0e77Sgovinda ASSERT(iv_p != NULL); 3197c478bd9Sstevel@tonic-gate 320*b0fc0e77Sgovinda if (iv_p->iv_flags & IV_SOFTINT_PEND) 321*b0fc0e77Sgovinda return (EIO); 3227c478bd9Sstevel@tonic-gate 323*b0fc0e77Sgovinda iv_p->iv_arg2 = intr_arg2; 324*b0fc0e77Sgovinda return (0); 3257c478bd9Sstevel@tonic-gate } 3267c478bd9Sstevel@tonic-gate 327*b0fc0e77Sgovinda /* 328*b0fc0e77Sgovinda * update_softint_pri() - Update softint priority. 329*b0fc0e77Sgovinda */ 3307c478bd9Sstevel@tonic-gate int 331*b0fc0e77Sgovinda update_softint_pri(uint64_t softint_id, uint_t pil) 3327c478bd9Sstevel@tonic-gate { 333*b0fc0e77Sgovinda intr_vec_t *iv_p = (intr_vec_t *)softint_id; 3347c478bd9Sstevel@tonic-gate 335*b0fc0e77Sgovinda ASSERT(iv_p != NULL); 3367c478bd9Sstevel@tonic-gate 337*b0fc0e77Sgovinda if (pil > PIL_MAX) 338*b0fc0e77Sgovinda return (EINVAL); 339*b0fc0e77Sgovinda 340*b0fc0e77Sgovinda iv_p->iv_pil = pil; 341*b0fc0e77Sgovinda return (0); 3427c478bd9Sstevel@tonic-gate } 343