112683SJimmy.Vetayases@oracle.com /* 212683SJimmy.Vetayases@oracle.com * CDDL HEADER START 312683SJimmy.Vetayases@oracle.com * 412683SJimmy.Vetayases@oracle.com * The contents of this file are subject to the terms of the 512683SJimmy.Vetayases@oracle.com * Common Development and Distribution License (the "License"). 612683SJimmy.Vetayases@oracle.com * You may not use this file except in compliance with the License. 712683SJimmy.Vetayases@oracle.com * 812683SJimmy.Vetayases@oracle.com * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 912683SJimmy.Vetayases@oracle.com * or http://www.opensolaris.org/os/licensing. 1012683SJimmy.Vetayases@oracle.com * See the License for the specific language governing permissions 1112683SJimmy.Vetayases@oracle.com * and limitations under the License. 1212683SJimmy.Vetayases@oracle.com * 1312683SJimmy.Vetayases@oracle.com * When distributing Covered Code, include this CDDL HEADER in each 1412683SJimmy.Vetayases@oracle.com * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1512683SJimmy.Vetayases@oracle.com * If applicable, add the following below this CDDL HEADER, with the 1612683SJimmy.Vetayases@oracle.com * fields enclosed by brackets "[]" replaced with your own identifying 1712683SJimmy.Vetayases@oracle.com * information: Portions Copyright [yyyy] [name of copyright owner] 1812683SJimmy.Vetayases@oracle.com * 1912683SJimmy.Vetayases@oracle.com * CDDL HEADER END 2012683SJimmy.Vetayases@oracle.com */ 2112683SJimmy.Vetayases@oracle.com 2212683SJimmy.Vetayases@oracle.com /* 2312683SJimmy.Vetayases@oracle.com * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 2412683SJimmy.Vetayases@oracle.com */ 2512683SJimmy.Vetayases@oracle.com /* 2612683SJimmy.Vetayases@oracle.com * Copyright (c) 2010, Intel Corporation. 2712683SJimmy.Vetayases@oracle.com * All rights reserved. 2812683SJimmy.Vetayases@oracle.com */ 2912683SJimmy.Vetayases@oracle.com 3012683SJimmy.Vetayases@oracle.com #include <sys/processor.h> 3112683SJimmy.Vetayases@oracle.com #include <sys/time.h> 3212683SJimmy.Vetayases@oracle.com #include <sys/psm.h> 3312683SJimmy.Vetayases@oracle.com #include <sys/smp_impldefs.h> 3412683SJimmy.Vetayases@oracle.com #include <sys/cram.h> 3512683SJimmy.Vetayases@oracle.com #include <sys/acpi/acpi.h> 3612683SJimmy.Vetayases@oracle.com #include <sys/acpica.h> 3712683SJimmy.Vetayases@oracle.com #include <sys/psm_common.h> 3812683SJimmy.Vetayases@oracle.com #include <sys/pit.h> 3912683SJimmy.Vetayases@oracle.com #include <sys/ddi.h> 4012683SJimmy.Vetayases@oracle.com #include <sys/sunddi.h> 4112683SJimmy.Vetayases@oracle.com #include <sys/ddi_impldefs.h> 4212683SJimmy.Vetayases@oracle.com #include <sys/pci.h> 4312683SJimmy.Vetayases@oracle.com #include <sys/promif.h> 4412683SJimmy.Vetayases@oracle.com #include <sys/x86_archext.h> 4512683SJimmy.Vetayases@oracle.com #include <sys/cpc_impl.h> 4612683SJimmy.Vetayases@oracle.com #include <sys/uadmin.h> 4712683SJimmy.Vetayases@oracle.com #include <sys/panic.h> 4812683SJimmy.Vetayases@oracle.com #include <sys/debug.h> 4912683SJimmy.Vetayases@oracle.com #include <sys/archsystm.h> 5012683SJimmy.Vetayases@oracle.com #include <sys/trap.h> 5112683SJimmy.Vetayases@oracle.com #include <sys/machsystm.h> 5212683SJimmy.Vetayases@oracle.com #include <sys/sysmacros.h> 5312683SJimmy.Vetayases@oracle.com #include <sys/cpuvar.h> 5412683SJimmy.Vetayases@oracle.com #include <sys/rm_platter.h> 5512683SJimmy.Vetayases@oracle.com #include <sys/privregs.h> 5612683SJimmy.Vetayases@oracle.com #include <sys/note.h> 5712683SJimmy.Vetayases@oracle.com #include <sys/pci_intr_lib.h> 5812683SJimmy.Vetayases@oracle.com #include <sys/spl.h> 5912683SJimmy.Vetayases@oracle.com #include <sys/clock.h> 6012683SJimmy.Vetayases@oracle.com #include <sys/dditypes.h> 6112683SJimmy.Vetayases@oracle.com #include <sys/sunddi.h> 6212683SJimmy.Vetayases@oracle.com #include <sys/x_call.h> 6312683SJimmy.Vetayases@oracle.com #include <sys/reboot.h> 6412683SJimmy.Vetayases@oracle.com #include <sys/apix.h> 6512683SJimmy.Vetayases@oracle.com 6612683SJimmy.Vetayases@oracle.com static int apix_get_avail_vector_oncpu(uint32_t, int, int); 6712683SJimmy.Vetayases@oracle.com static apix_vector_t *apix_init_vector(processorid_t, uchar_t); 6812683SJimmy.Vetayases@oracle.com static void apix_cleanup_vector(apix_vector_t *); 6912683SJimmy.Vetayases@oracle.com static void apix_insert_av(apix_vector_t *, void *, avfunc, caddr_t, caddr_t, 7012683SJimmy.Vetayases@oracle.com uint64_t *, int, dev_info_t *); 7112683SJimmy.Vetayases@oracle.com static void apix_remove_av(apix_vector_t *, struct autovec *); 7212683SJimmy.Vetayases@oracle.com static void apix_clear_dev_map(dev_info_t *, int, int); 7312683SJimmy.Vetayases@oracle.com static boolean_t apix_is_cpu_enabled(processorid_t); 7412683SJimmy.Vetayases@oracle.com static void apix_wait_till_seen(processorid_t, int); 7512683SJimmy.Vetayases@oracle.com 7612683SJimmy.Vetayases@oracle.com #define GET_INTR_INUM(ihdlp) \ 7712683SJimmy.Vetayases@oracle.com (((ihdlp) != NULL) ? ((ddi_intr_handle_impl_t *)(ihdlp))->ih_inum : 0) 7812683SJimmy.Vetayases@oracle.com 7912683SJimmy.Vetayases@oracle.com apix_rebind_info_t apix_rebindinfo = {0, 0, 0, NULL, 0, NULL}; 8012683SJimmy.Vetayases@oracle.com 8112683SJimmy.Vetayases@oracle.com /* 8212683SJimmy.Vetayases@oracle.com * Allocate IPI 8312683SJimmy.Vetayases@oracle.com * 8412683SJimmy.Vetayases@oracle.com * Return vector number or 0 on error 8512683SJimmy.Vetayases@oracle.com */ 8612683SJimmy.Vetayases@oracle.com uchar_t 8712683SJimmy.Vetayases@oracle.com apix_alloc_ipi(int ipl) 8812683SJimmy.Vetayases@oracle.com { 8912683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 9012683SJimmy.Vetayases@oracle.com uchar_t vector; 9112683SJimmy.Vetayases@oracle.com int cpun; 9212683SJimmy.Vetayases@oracle.com int nproc; 9312683SJimmy.Vetayases@oracle.com 9412683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(0); 9512683SJimmy.Vetayases@oracle.com 9612683SJimmy.Vetayases@oracle.com vector = apix_get_avail_vector_oncpu(0, APIX_IPI_MIN, APIX_IPI_MAX); 9712683SJimmy.Vetayases@oracle.com if (vector == 0) { 9812683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(0); 9912683SJimmy.Vetayases@oracle.com cmn_err(CE_WARN, "apix: no available IPI\n"); 10012683SJimmy.Vetayases@oracle.com apic_error |= APIC_ERR_GET_IPIVECT_FAIL; 10112683SJimmy.Vetayases@oracle.com return (0); 10212683SJimmy.Vetayases@oracle.com } 10312683SJimmy.Vetayases@oracle.com 10412683SJimmy.Vetayases@oracle.com nproc = max(apic_nproc, apic_max_nproc); 10512683SJimmy.Vetayases@oracle.com for (cpun = 0; cpun < nproc; cpun++) { 10612683SJimmy.Vetayases@oracle.com vecp = xv_vector(cpun, vector); 10712683SJimmy.Vetayases@oracle.com if (vecp == NULL) { 10812683SJimmy.Vetayases@oracle.com vecp = kmem_zalloc(sizeof (apix_vector_t), KM_NOSLEEP); 10912683SJimmy.Vetayases@oracle.com if (vecp == NULL) { 11012683SJimmy.Vetayases@oracle.com cmn_err(CE_WARN, "apix: No memory for ipi"); 11112683SJimmy.Vetayases@oracle.com goto fail; 11212683SJimmy.Vetayases@oracle.com } 11312683SJimmy.Vetayases@oracle.com xv_vector(cpun, vector) = vecp; 11412683SJimmy.Vetayases@oracle.com } 11512683SJimmy.Vetayases@oracle.com vecp->v_state = APIX_STATE_ALLOCED; 11612683SJimmy.Vetayases@oracle.com vecp->v_type = APIX_TYPE_IPI; 11712683SJimmy.Vetayases@oracle.com vecp->v_cpuid = vecp->v_bound_cpuid = cpun; 11812683SJimmy.Vetayases@oracle.com vecp->v_vector = vector; 11912683SJimmy.Vetayases@oracle.com vecp->v_pri = ipl; 12012683SJimmy.Vetayases@oracle.com } 12112683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(0); 12212683SJimmy.Vetayases@oracle.com return (vector); 12312683SJimmy.Vetayases@oracle.com 12412683SJimmy.Vetayases@oracle.com fail: 12512683SJimmy.Vetayases@oracle.com while (--cpun >= 0) 12612683SJimmy.Vetayases@oracle.com apix_cleanup_vector(xv_vector(cpun, vector)); 12712683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(0); 12812683SJimmy.Vetayases@oracle.com return (0); 12912683SJimmy.Vetayases@oracle.com } 13012683SJimmy.Vetayases@oracle.com 13112683SJimmy.Vetayases@oracle.com /* 13212683SJimmy.Vetayases@oracle.com * Add IPI service routine 13312683SJimmy.Vetayases@oracle.com */ 13412683SJimmy.Vetayases@oracle.com static int 13512683SJimmy.Vetayases@oracle.com apix_add_ipi(int ipl, avfunc xxintr, char *name, int vector, 13612683SJimmy.Vetayases@oracle.com caddr_t arg1, caddr_t arg2) 13712683SJimmy.Vetayases@oracle.com { 13812683SJimmy.Vetayases@oracle.com int cpun; 13912683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 14012683SJimmy.Vetayases@oracle.com int nproc; 14112683SJimmy.Vetayases@oracle.com 14212683SJimmy.Vetayases@oracle.com ASSERT(vector >= APIX_IPI_MIN && vector <= APIX_IPI_MAX); 14312683SJimmy.Vetayases@oracle.com 14412683SJimmy.Vetayases@oracle.com nproc = max(apic_nproc, apic_max_nproc); 14512683SJimmy.Vetayases@oracle.com for (cpun = 0; cpun < nproc; cpun++) { 14612683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(cpun); 14712683SJimmy.Vetayases@oracle.com vecp = xv_vector(cpun, vector); 14812683SJimmy.Vetayases@oracle.com apix_insert_av(vecp, NULL, xxintr, arg1, arg2, NULL, ipl, NULL); 14912683SJimmy.Vetayases@oracle.com vecp->v_state = APIX_STATE_ENABLED; 15012683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(cpun); 15112683SJimmy.Vetayases@oracle.com } 15212683SJimmy.Vetayases@oracle.com 15312683SJimmy.Vetayases@oracle.com APIC_VERBOSE(IPI, (CE_CONT, "apix: add ipi for %s, vector %x " 15412683SJimmy.Vetayases@oracle.com "ipl %x\n", name, vector, ipl)); 15512683SJimmy.Vetayases@oracle.com 15612683SJimmy.Vetayases@oracle.com return (1); 15712683SJimmy.Vetayases@oracle.com } 15812683SJimmy.Vetayases@oracle.com 15912683SJimmy.Vetayases@oracle.com /* 16012683SJimmy.Vetayases@oracle.com * Find and return first free vector in range (start, end) 16112683SJimmy.Vetayases@oracle.com */ 16212683SJimmy.Vetayases@oracle.com static int 16312683SJimmy.Vetayases@oracle.com apix_get_avail_vector_oncpu(uint32_t cpuid, int start, int end) 16412683SJimmy.Vetayases@oracle.com { 16512683SJimmy.Vetayases@oracle.com int i; 16612683SJimmy.Vetayases@oracle.com apix_impl_t *apixp = apixs[cpuid]; 16712683SJimmy.Vetayases@oracle.com 16812683SJimmy.Vetayases@oracle.com for (i = start; i <= end; i++) { 16912683SJimmy.Vetayases@oracle.com if (APIC_CHECK_RESERVE_VECTORS(i)) 17012683SJimmy.Vetayases@oracle.com continue; 17112683SJimmy.Vetayases@oracle.com if (IS_VECT_FREE(apixp->x_vectbl[i])) 17212683SJimmy.Vetayases@oracle.com return (i); 17312683SJimmy.Vetayases@oracle.com } 17412683SJimmy.Vetayases@oracle.com 17512683SJimmy.Vetayases@oracle.com return (0); 17612683SJimmy.Vetayases@oracle.com } 17712683SJimmy.Vetayases@oracle.com 17812683SJimmy.Vetayases@oracle.com /* 17912683SJimmy.Vetayases@oracle.com * Allocate a vector on specified cpu 18012683SJimmy.Vetayases@oracle.com * 18112683SJimmy.Vetayases@oracle.com * Return NULL on error 18212683SJimmy.Vetayases@oracle.com */ 18312683SJimmy.Vetayases@oracle.com static apix_vector_t * 18412683SJimmy.Vetayases@oracle.com apix_alloc_vector_oncpu(uint32_t cpuid, dev_info_t *dip, int inum, int type) 18512683SJimmy.Vetayases@oracle.com { 18612683SJimmy.Vetayases@oracle.com processorid_t tocpu = cpuid & ~IRQ_USER_BOUND; 18712683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 18812683SJimmy.Vetayases@oracle.com int vector; 18912683SJimmy.Vetayases@oracle.com 19012683SJimmy.Vetayases@oracle.com ASSERT(APIX_CPU_LOCK_HELD(tocpu)); 19112683SJimmy.Vetayases@oracle.com 19212683SJimmy.Vetayases@oracle.com /* find free vector */ 19312683SJimmy.Vetayases@oracle.com vector = apix_get_avail_vector_oncpu(tocpu, APIX_AVINTR_MIN, 19412683SJimmy.Vetayases@oracle.com APIX_AVINTR_MAX); 19512683SJimmy.Vetayases@oracle.com if (vector == 0) 19612683SJimmy.Vetayases@oracle.com return (NULL); 19712683SJimmy.Vetayases@oracle.com 19812683SJimmy.Vetayases@oracle.com vecp = apix_init_vector(tocpu, vector); 19912683SJimmy.Vetayases@oracle.com vecp->v_type = (ushort_t)type; 20012683SJimmy.Vetayases@oracle.com vecp->v_inum = inum; 20112683SJimmy.Vetayases@oracle.com vecp->v_flags = (cpuid & IRQ_USER_BOUND) ? APIX_VECT_USER_BOUND : 0; 20212683SJimmy.Vetayases@oracle.com 20312683SJimmy.Vetayases@oracle.com if (dip != NULL) 20412683SJimmy.Vetayases@oracle.com apix_set_dev_map(vecp, dip, inum); 20512683SJimmy.Vetayases@oracle.com 20612683SJimmy.Vetayases@oracle.com return (vecp); 20712683SJimmy.Vetayases@oracle.com } 20812683SJimmy.Vetayases@oracle.com 20912683SJimmy.Vetayases@oracle.com /* 21012683SJimmy.Vetayases@oracle.com * Allocates "count" contiguous MSI vectors starting at the proper alignment. 21112683SJimmy.Vetayases@oracle.com * Caller needs to make sure that count has to be power of 2 and should not 21212683SJimmy.Vetayases@oracle.com * be < 1. 21312683SJimmy.Vetayases@oracle.com * 21412683SJimmy.Vetayases@oracle.com * Return first vector number 21512683SJimmy.Vetayases@oracle.com */ 21612683SJimmy.Vetayases@oracle.com apix_vector_t * 21712683SJimmy.Vetayases@oracle.com apix_alloc_nvectors_oncpu(uint32_t cpuid, dev_info_t *dip, int inum, 21812683SJimmy.Vetayases@oracle.com int count, int type) 21912683SJimmy.Vetayases@oracle.com { 22012683SJimmy.Vetayases@oracle.com int i, msibits, start = 0, navail = 0; 22112683SJimmy.Vetayases@oracle.com apix_vector_t *vecp, *startp = NULL; 22212683SJimmy.Vetayases@oracle.com processorid_t tocpu = cpuid & ~IRQ_USER_BOUND; 22312683SJimmy.Vetayases@oracle.com uint_t flags; 22412683SJimmy.Vetayases@oracle.com 22512683SJimmy.Vetayases@oracle.com ASSERT(APIX_CPU_LOCK_HELD(tocpu)); 22612683SJimmy.Vetayases@oracle.com 22712683SJimmy.Vetayases@oracle.com /* 22812683SJimmy.Vetayases@oracle.com * msibits is the no. of lower order message data bits for the 22912683SJimmy.Vetayases@oracle.com * allocated MSI vectors and is used to calculate the aligned 23012683SJimmy.Vetayases@oracle.com * starting vector 23112683SJimmy.Vetayases@oracle.com */ 23212683SJimmy.Vetayases@oracle.com msibits = count - 1; 23312683SJimmy.Vetayases@oracle.com 23412683SJimmy.Vetayases@oracle.com /* It has to be contiguous */ 23512683SJimmy.Vetayases@oracle.com for (i = APIX_AVINTR_MIN; i <= APIX_AVINTR_MAX; i++) { 23612683SJimmy.Vetayases@oracle.com if (!IS_VECT_FREE(xv_vector(tocpu, i))) 23712683SJimmy.Vetayases@oracle.com continue; 23812683SJimmy.Vetayases@oracle.com 23912683SJimmy.Vetayases@oracle.com /* 24012683SJimmy.Vetayases@oracle.com * starting vector has to be aligned accordingly for 24112683SJimmy.Vetayases@oracle.com * multiple MSIs 24212683SJimmy.Vetayases@oracle.com */ 24312683SJimmy.Vetayases@oracle.com if (msibits) 24412683SJimmy.Vetayases@oracle.com i = (i + msibits) & ~msibits; 24512683SJimmy.Vetayases@oracle.com 24612683SJimmy.Vetayases@oracle.com for (navail = 0, start = i; i <= APIX_AVINTR_MAX; i++) { 24712683SJimmy.Vetayases@oracle.com if (!IS_VECT_FREE(xv_vector(tocpu, i))) 24812683SJimmy.Vetayases@oracle.com break; 24912683SJimmy.Vetayases@oracle.com if (APIC_CHECK_RESERVE_VECTORS(i)) 25012683SJimmy.Vetayases@oracle.com break; 25112683SJimmy.Vetayases@oracle.com if (++navail == count) 25212683SJimmy.Vetayases@oracle.com goto done; 25312683SJimmy.Vetayases@oracle.com } 25412683SJimmy.Vetayases@oracle.com } 25512683SJimmy.Vetayases@oracle.com 25612683SJimmy.Vetayases@oracle.com return (NULL); 25712683SJimmy.Vetayases@oracle.com 25812683SJimmy.Vetayases@oracle.com done: 25912683SJimmy.Vetayases@oracle.com flags = (cpuid & IRQ_USER_BOUND) ? APIX_VECT_USER_BOUND : 0; 26012683SJimmy.Vetayases@oracle.com 26112683SJimmy.Vetayases@oracle.com for (i = 0; i < count; i++) { 26212683SJimmy.Vetayases@oracle.com if ((vecp = apix_init_vector(tocpu, start + i)) == NULL) 26312683SJimmy.Vetayases@oracle.com goto fail; 26412683SJimmy.Vetayases@oracle.com 26512683SJimmy.Vetayases@oracle.com vecp->v_type = (ushort_t)type; 26612683SJimmy.Vetayases@oracle.com vecp->v_inum = inum + i; 26712683SJimmy.Vetayases@oracle.com vecp->v_flags = flags; 26812683SJimmy.Vetayases@oracle.com 26912683SJimmy.Vetayases@oracle.com if (dip != NULL) 27012683SJimmy.Vetayases@oracle.com apix_set_dev_map(vecp, dip, inum + i); 27112683SJimmy.Vetayases@oracle.com 27212683SJimmy.Vetayases@oracle.com if (i == 0) 27312683SJimmy.Vetayases@oracle.com startp = vecp; 27412683SJimmy.Vetayases@oracle.com } 27512683SJimmy.Vetayases@oracle.com 27612683SJimmy.Vetayases@oracle.com return (startp); 27712683SJimmy.Vetayases@oracle.com 27812683SJimmy.Vetayases@oracle.com fail: 27912683SJimmy.Vetayases@oracle.com while (i-- > 0) { /* Free allocated vectors */ 28012683SJimmy.Vetayases@oracle.com vecp = xv_vector(tocpu, start + i); 28112683SJimmy.Vetayases@oracle.com apix_clear_dev_map(dip, inum + i, type); 28212683SJimmy.Vetayases@oracle.com apix_cleanup_vector(vecp); 28312683SJimmy.Vetayases@oracle.com } 28412683SJimmy.Vetayases@oracle.com return (NULL); 28512683SJimmy.Vetayases@oracle.com } 28612683SJimmy.Vetayases@oracle.com 28712683SJimmy.Vetayases@oracle.com #define APIX_WRITE_MSI_DATA(_hdl, _cap, _ctrl, _v)\ 28812683SJimmy.Vetayases@oracle.com do {\ 28912683SJimmy.Vetayases@oracle.com if ((_ctrl) & PCI_MSI_64BIT_MASK)\ 29012683SJimmy.Vetayases@oracle.com pci_config_put16((_hdl), (_cap) + PCI_MSI_64BIT_DATA, (_v));\ 29112683SJimmy.Vetayases@oracle.com else\ 29212683SJimmy.Vetayases@oracle.com pci_config_put16((_hdl), (_cap) + PCI_MSI_32BIT_DATA, (_v));\ 29312683SJimmy.Vetayases@oracle.com _NOTE(CONSTCOND)} while (0) 29412683SJimmy.Vetayases@oracle.com 29512683SJimmy.Vetayases@oracle.com static void 29612683SJimmy.Vetayases@oracle.com apix_pci_msi_enable_vector(apix_vector_t *vecp, dev_info_t *dip, int type, 29712683SJimmy.Vetayases@oracle.com int inum, int count, uchar_t vector, int target_apic_id) 29812683SJimmy.Vetayases@oracle.com { 29912683SJimmy.Vetayases@oracle.com uint64_t msi_addr, msi_data; 30012683SJimmy.Vetayases@oracle.com ushort_t msi_ctrl; 30112683SJimmy.Vetayases@oracle.com int i, cap_ptr = i_ddi_get_msi_msix_cap_ptr(dip); 30212683SJimmy.Vetayases@oracle.com ddi_acc_handle_t handle = i_ddi_get_pci_config_handle(dip); 30312683SJimmy.Vetayases@oracle.com msi_regs_t msi_regs; 30412683SJimmy.Vetayases@oracle.com void *intrmap_tbl[PCI_MSI_MAX_INTRS]; 30512683SJimmy.Vetayases@oracle.com 30612683SJimmy.Vetayases@oracle.com DDI_INTR_IMPLDBG((CE_CONT, "apix_pci_msi_enable_vector: dip=0x%p\n" 30712683SJimmy.Vetayases@oracle.com "\tdriver = %s, inum=0x%x vector=0x%x apicid=0x%x\n", (void *)dip, 30812683SJimmy.Vetayases@oracle.com ddi_driver_name(dip), inum, vector, target_apic_id)); 30912683SJimmy.Vetayases@oracle.com 31012683SJimmy.Vetayases@oracle.com ASSERT((handle != NULL) && (cap_ptr != 0)); 31112683SJimmy.Vetayases@oracle.com 31212683SJimmy.Vetayases@oracle.com msi_regs.mr_data = vector; 31312683SJimmy.Vetayases@oracle.com msi_regs.mr_addr = target_apic_id; 31412683SJimmy.Vetayases@oracle.com 31512683SJimmy.Vetayases@oracle.com intrmap_tbl[0] = vecp->v_intrmap_private; 31612683SJimmy.Vetayases@oracle.com apic_vt_ops->apic_intrmap_alloc_entry(intrmap_tbl, dip, type, 31712683SJimmy.Vetayases@oracle.com count, 0xff); 31812683SJimmy.Vetayases@oracle.com for (i = 0; i < count; i++) 31912683SJimmy.Vetayases@oracle.com xv_intrmap_private(vecp->v_cpuid, vector + i) = intrmap_tbl[i]; 32012683SJimmy.Vetayases@oracle.com 32112683SJimmy.Vetayases@oracle.com apic_vt_ops->apic_intrmap_map_entry(vecp->v_intrmap_private, 32212683SJimmy.Vetayases@oracle.com (void *)&msi_regs, type, count); 32312683SJimmy.Vetayases@oracle.com apic_vt_ops->apic_intrmap_record_msi(vecp->v_intrmap_private, 32412683SJimmy.Vetayases@oracle.com &msi_regs); 32512683SJimmy.Vetayases@oracle.com 32612683SJimmy.Vetayases@oracle.com /* MSI Address */ 32712683SJimmy.Vetayases@oracle.com msi_addr = msi_regs.mr_addr; 32812683SJimmy.Vetayases@oracle.com 32912683SJimmy.Vetayases@oracle.com /* MSI Data: MSI is edge triggered according to spec */ 33012683SJimmy.Vetayases@oracle.com msi_data = msi_regs.mr_data; 33112683SJimmy.Vetayases@oracle.com 33212683SJimmy.Vetayases@oracle.com DDI_INTR_IMPLDBG((CE_CONT, "apix_pci_msi_enable_vector: addr=0x%lx " 33312683SJimmy.Vetayases@oracle.com "data=0x%lx\n", (long)msi_addr, (long)msi_data)); 33412683SJimmy.Vetayases@oracle.com 33512683SJimmy.Vetayases@oracle.com if (type == APIX_TYPE_MSI) { 33612683SJimmy.Vetayases@oracle.com msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL); 33712683SJimmy.Vetayases@oracle.com 33812683SJimmy.Vetayases@oracle.com /* Set the bits to inform how many MSIs are enabled */ 33912683SJimmy.Vetayases@oracle.com msi_ctrl |= ((highbit(count) - 1) << PCI_MSI_MME_SHIFT); 34012683SJimmy.Vetayases@oracle.com pci_config_put16(handle, cap_ptr + PCI_MSI_CTRL, msi_ctrl); 34112683SJimmy.Vetayases@oracle.com 34212683SJimmy.Vetayases@oracle.com if ((vecp->v_flags & APIX_VECT_MASKABLE) == 0) 34312683SJimmy.Vetayases@oracle.com APIX_WRITE_MSI_DATA(handle, cap_ptr, msi_ctrl, 34412683SJimmy.Vetayases@oracle.com APIX_RESV_VECTOR); 34512683SJimmy.Vetayases@oracle.com 34612683SJimmy.Vetayases@oracle.com pci_config_put32(handle, 34712683SJimmy.Vetayases@oracle.com cap_ptr + PCI_MSI_ADDR_OFFSET, msi_addr); 34812683SJimmy.Vetayases@oracle.com if (msi_ctrl & PCI_MSI_64BIT_MASK) 34912683SJimmy.Vetayases@oracle.com pci_config_put32(handle, 35012683SJimmy.Vetayases@oracle.com cap_ptr + PCI_MSI_ADDR_OFFSET + 4, msi_addr >> 32); 35112683SJimmy.Vetayases@oracle.com 35212683SJimmy.Vetayases@oracle.com APIX_WRITE_MSI_DATA(handle, cap_ptr, msi_ctrl, msi_data); 35312683SJimmy.Vetayases@oracle.com } else if (type == APIX_TYPE_MSIX) { 35412683SJimmy.Vetayases@oracle.com uintptr_t off; 35512683SJimmy.Vetayases@oracle.com ddi_intr_msix_t *msix_p = i_ddi_get_msix(dip); 35612683SJimmy.Vetayases@oracle.com 35712683SJimmy.Vetayases@oracle.com /* Offset into the "inum"th entry in the MSI-X table */ 35812683SJimmy.Vetayases@oracle.com off = (uintptr_t)msix_p->msix_tbl_addr + 35912683SJimmy.Vetayases@oracle.com (inum * PCI_MSIX_VECTOR_SIZE); 36012683SJimmy.Vetayases@oracle.com 36112683SJimmy.Vetayases@oracle.com ddi_put32(msix_p->msix_tbl_hdl, 36212683SJimmy.Vetayases@oracle.com (uint32_t *)(off + PCI_MSIX_DATA_OFFSET), msi_data); 36312683SJimmy.Vetayases@oracle.com ddi_put64(msix_p->msix_tbl_hdl, 36412683SJimmy.Vetayases@oracle.com (uint64_t *)(off + PCI_MSIX_LOWER_ADDR_OFFSET), msi_addr); 36512683SJimmy.Vetayases@oracle.com } 36612683SJimmy.Vetayases@oracle.com } 36712683SJimmy.Vetayases@oracle.com 36812683SJimmy.Vetayases@oracle.com static void 36912683SJimmy.Vetayases@oracle.com apix_pci_msi_enable_mode(dev_info_t *dip, int type, int inum) 37012683SJimmy.Vetayases@oracle.com { 37112683SJimmy.Vetayases@oracle.com ushort_t msi_ctrl; 37212683SJimmy.Vetayases@oracle.com int cap_ptr = i_ddi_get_msi_msix_cap_ptr(dip); 37312683SJimmy.Vetayases@oracle.com ddi_acc_handle_t handle = i_ddi_get_pci_config_handle(dip); 37412683SJimmy.Vetayases@oracle.com 37512683SJimmy.Vetayases@oracle.com ASSERT((handle != NULL) && (cap_ptr != 0)); 37612683SJimmy.Vetayases@oracle.com 37712683SJimmy.Vetayases@oracle.com if (type == APIX_TYPE_MSI) { 37812683SJimmy.Vetayases@oracle.com msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL); 37912683SJimmy.Vetayases@oracle.com if ((msi_ctrl & PCI_MSI_ENABLE_BIT)) 38012683SJimmy.Vetayases@oracle.com return; 38112683SJimmy.Vetayases@oracle.com 38212683SJimmy.Vetayases@oracle.com msi_ctrl |= PCI_MSI_ENABLE_BIT; 38312683SJimmy.Vetayases@oracle.com pci_config_put16(handle, cap_ptr + PCI_MSI_CTRL, msi_ctrl); 38412683SJimmy.Vetayases@oracle.com 38512683SJimmy.Vetayases@oracle.com } else if (type == DDI_INTR_TYPE_MSIX) { 38612683SJimmy.Vetayases@oracle.com uintptr_t off; 38712683SJimmy.Vetayases@oracle.com uint32_t mask; 38812683SJimmy.Vetayases@oracle.com ddi_intr_msix_t *msix_p; 38912683SJimmy.Vetayases@oracle.com 39012683SJimmy.Vetayases@oracle.com msix_p = i_ddi_get_msix(dip); 39112683SJimmy.Vetayases@oracle.com 39212683SJimmy.Vetayases@oracle.com /* Offset into "inum"th entry in the MSI-X table & clear mask */ 39312683SJimmy.Vetayases@oracle.com off = (uintptr_t)msix_p->msix_tbl_addr + (inum * 39412683SJimmy.Vetayases@oracle.com PCI_MSIX_VECTOR_SIZE) + PCI_MSIX_VECTOR_CTRL_OFFSET; 39512683SJimmy.Vetayases@oracle.com 39612683SJimmy.Vetayases@oracle.com mask = ddi_get32(msix_p->msix_tbl_hdl, (uint32_t *)off); 39712683SJimmy.Vetayases@oracle.com 39812683SJimmy.Vetayases@oracle.com ddi_put32(msix_p->msix_tbl_hdl, (uint32_t *)off, (mask & ~1)); 39912683SJimmy.Vetayases@oracle.com 40012683SJimmy.Vetayases@oracle.com msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSIX_CTRL); 40112683SJimmy.Vetayases@oracle.com 40212683SJimmy.Vetayases@oracle.com if (!(msi_ctrl & PCI_MSIX_ENABLE_BIT)) { 40312683SJimmy.Vetayases@oracle.com msi_ctrl |= PCI_MSIX_ENABLE_BIT; 40412683SJimmy.Vetayases@oracle.com pci_config_put16(handle, cap_ptr + PCI_MSIX_CTRL, 40512683SJimmy.Vetayases@oracle.com msi_ctrl); 40612683SJimmy.Vetayases@oracle.com } 40712683SJimmy.Vetayases@oracle.com } 40812683SJimmy.Vetayases@oracle.com } 40912683SJimmy.Vetayases@oracle.com 41012683SJimmy.Vetayases@oracle.com /* 41112683SJimmy.Vetayases@oracle.com * Setup interrupt, pogramming IO-APIC or MSI/X address/data. 41212683SJimmy.Vetayases@oracle.com */ 41312683SJimmy.Vetayases@oracle.com void 41412683SJimmy.Vetayases@oracle.com apix_enable_vector(apix_vector_t *vecp) 41512683SJimmy.Vetayases@oracle.com { 41612683SJimmy.Vetayases@oracle.com int tocpu = vecp->v_cpuid, type = vecp->v_type; 41712683SJimmy.Vetayases@oracle.com apic_cpus_info_t *cpu_infop; 41812683SJimmy.Vetayases@oracle.com ulong_t iflag; 41912683SJimmy.Vetayases@oracle.com 42012683SJimmy.Vetayases@oracle.com ASSERT(tocpu < apic_nproc); 42112683SJimmy.Vetayases@oracle.com 42212683SJimmy.Vetayases@oracle.com cpu_infop = &apic_cpus[tocpu]; 42312683SJimmy.Vetayases@oracle.com if (vecp->v_flags & APIX_VECT_USER_BOUND) 42412683SJimmy.Vetayases@oracle.com cpu_infop->aci_bound++; 42512683SJimmy.Vetayases@oracle.com else 42612683SJimmy.Vetayases@oracle.com cpu_infop->aci_temp_bound++; 42712683SJimmy.Vetayases@oracle.com 42812683SJimmy.Vetayases@oracle.com iflag = intr_clear(); 42912683SJimmy.Vetayases@oracle.com lock_set(&apic_ioapic_lock); 43012683SJimmy.Vetayases@oracle.com 43112683SJimmy.Vetayases@oracle.com if (!DDI_INTR_IS_MSI_OR_MSIX(type)) { /* fixed */ 43212683SJimmy.Vetayases@oracle.com apix_intx_enable(vecp->v_inum); 43312683SJimmy.Vetayases@oracle.com } else { 43412683SJimmy.Vetayases@oracle.com int inum = vecp->v_inum; 43512683SJimmy.Vetayases@oracle.com dev_info_t *dip = APIX_GET_DIP(vecp); 43612683SJimmy.Vetayases@oracle.com int count = i_ddi_intr_get_current_nintrs(dip); 43712683SJimmy.Vetayases@oracle.com 43812683SJimmy.Vetayases@oracle.com if (type == APIX_TYPE_MSI) { /* MSI */ 43912683SJimmy.Vetayases@oracle.com if (inum == apix_get_max_dev_inum(dip, type)) { 44012683SJimmy.Vetayases@oracle.com /* last one */ 44112683SJimmy.Vetayases@oracle.com uchar_t start_inum = inum + 1 - count; 44212683SJimmy.Vetayases@oracle.com uchar_t start_vect = vecp->v_vector + 1 - count; 44312683SJimmy.Vetayases@oracle.com apix_vector_t *start_vecp = 44412683SJimmy.Vetayases@oracle.com xv_vector(vecp->v_cpuid, start_vect); 44512683SJimmy.Vetayases@oracle.com 44612683SJimmy.Vetayases@oracle.com APIC_VERBOSE(INTR, (CE_CONT, "apix: call " 44712683SJimmy.Vetayases@oracle.com "apix_pci_msi_enable_vector\n")); 44812683SJimmy.Vetayases@oracle.com apix_pci_msi_enable_vector(start_vecp, dip, 44912683SJimmy.Vetayases@oracle.com type, start_inum, count, start_vect, 45012683SJimmy.Vetayases@oracle.com cpu_infop->aci_local_id); 45112683SJimmy.Vetayases@oracle.com 45212683SJimmy.Vetayases@oracle.com APIC_VERBOSE(INTR, (CE_CONT, "apix: call " 45312683SJimmy.Vetayases@oracle.com "apix_pci_msi_enable_mode\n")); 45412683SJimmy.Vetayases@oracle.com apix_pci_msi_enable_mode(dip, type, inum); 45512683SJimmy.Vetayases@oracle.com } 45612683SJimmy.Vetayases@oracle.com } else { /* MSI-X */ 45712683SJimmy.Vetayases@oracle.com apix_pci_msi_enable_vector(vecp, dip, 45812683SJimmy.Vetayases@oracle.com type, inum, 1, vecp->v_vector, 45912683SJimmy.Vetayases@oracle.com cpu_infop->aci_local_id); 46012683SJimmy.Vetayases@oracle.com apix_pci_msi_enable_mode(dip, type, inum); 46112683SJimmy.Vetayases@oracle.com } 46212683SJimmy.Vetayases@oracle.com } 46312683SJimmy.Vetayases@oracle.com vecp->v_state = APIX_STATE_ENABLED; 46412683SJimmy.Vetayases@oracle.com apic_redist_cpu_skip &= ~(1 << tocpu); 46512683SJimmy.Vetayases@oracle.com 46612683SJimmy.Vetayases@oracle.com lock_clear(&apic_ioapic_lock); 46712683SJimmy.Vetayases@oracle.com intr_restore(iflag); 46812683SJimmy.Vetayases@oracle.com } 46912683SJimmy.Vetayases@oracle.com 47012683SJimmy.Vetayases@oracle.com /* 47112683SJimmy.Vetayases@oracle.com * Disable the interrupt 47212683SJimmy.Vetayases@oracle.com */ 47312683SJimmy.Vetayases@oracle.com void 47412683SJimmy.Vetayases@oracle.com apix_disable_vector(apix_vector_t *vecp) 47512683SJimmy.Vetayases@oracle.com { 47612683SJimmy.Vetayases@oracle.com struct autovec *avp = vecp->v_autovect; 47712683SJimmy.Vetayases@oracle.com ulong_t iflag; 47812683SJimmy.Vetayases@oracle.com 47912683SJimmy.Vetayases@oracle.com ASSERT(avp != NULL); 48012683SJimmy.Vetayases@oracle.com 48112683SJimmy.Vetayases@oracle.com iflag = intr_clear(); 48212683SJimmy.Vetayases@oracle.com lock_set(&apic_ioapic_lock); 48312683SJimmy.Vetayases@oracle.com 48412683SJimmy.Vetayases@oracle.com switch (vecp->v_type) { 48512683SJimmy.Vetayases@oracle.com case APIX_TYPE_MSI: 48612683SJimmy.Vetayases@oracle.com ASSERT(avp->av_vector != NULL && avp->av_dip != NULL); 48712683SJimmy.Vetayases@oracle.com /* 48812683SJimmy.Vetayases@oracle.com * Disable the MSI vector 48912683SJimmy.Vetayases@oracle.com * Make sure we only disable on the last 49012683SJimmy.Vetayases@oracle.com * of the multi-MSI support 49112683SJimmy.Vetayases@oracle.com */ 49212683SJimmy.Vetayases@oracle.com if (i_ddi_intr_get_current_nenables(avp->av_dip) == 1) { 49312683SJimmy.Vetayases@oracle.com apic_pci_msi_disable_mode(avp->av_dip, 49412683SJimmy.Vetayases@oracle.com DDI_INTR_TYPE_MSI); 49512683SJimmy.Vetayases@oracle.com } 49612683SJimmy.Vetayases@oracle.com break; 49712683SJimmy.Vetayases@oracle.com case APIX_TYPE_MSIX: 49812683SJimmy.Vetayases@oracle.com ASSERT(avp->av_vector != NULL && avp->av_dip != NULL); 49912683SJimmy.Vetayases@oracle.com /* 50012683SJimmy.Vetayases@oracle.com * Disable the MSI-X vector 50112683SJimmy.Vetayases@oracle.com * needs to clear its mask and addr/data for each MSI-X 50212683SJimmy.Vetayases@oracle.com */ 50312683SJimmy.Vetayases@oracle.com apic_pci_msi_unconfigure(avp->av_dip, DDI_INTR_TYPE_MSIX, 50412683SJimmy.Vetayases@oracle.com vecp->v_inum); 50512683SJimmy.Vetayases@oracle.com /* 50612683SJimmy.Vetayases@oracle.com * Make sure we only disable on the last MSI-X 50712683SJimmy.Vetayases@oracle.com */ 50812683SJimmy.Vetayases@oracle.com if (i_ddi_intr_get_current_nenables(avp->av_dip) == 1) { 50912683SJimmy.Vetayases@oracle.com apic_pci_msi_disable_mode(avp->av_dip, 51012683SJimmy.Vetayases@oracle.com DDI_INTR_TYPE_MSIX); 51112683SJimmy.Vetayases@oracle.com } 51212683SJimmy.Vetayases@oracle.com break; 51312683SJimmy.Vetayases@oracle.com default: 51412683SJimmy.Vetayases@oracle.com apix_intx_disable(vecp->v_inum); 51512683SJimmy.Vetayases@oracle.com break; 51612683SJimmy.Vetayases@oracle.com } 51712683SJimmy.Vetayases@oracle.com 51812683SJimmy.Vetayases@oracle.com if (!(apic_cpus[vecp->v_cpuid].aci_status & APIC_CPU_SUSPEND)) 51912683SJimmy.Vetayases@oracle.com vecp->v_state = APIX_STATE_DISABLED; 52012683SJimmy.Vetayases@oracle.com apic_vt_ops->apic_intrmap_free_entry(&vecp->v_intrmap_private); 52112683SJimmy.Vetayases@oracle.com vecp->v_intrmap_private = NULL; 52212683SJimmy.Vetayases@oracle.com 52312683SJimmy.Vetayases@oracle.com lock_clear(&apic_ioapic_lock); 52412683SJimmy.Vetayases@oracle.com intr_restore(iflag); 52512683SJimmy.Vetayases@oracle.com } 52612683SJimmy.Vetayases@oracle.com 52712683SJimmy.Vetayases@oracle.com /* 52812683SJimmy.Vetayases@oracle.com * Mark vector as obsoleted or freed. The vector is marked 52912683SJimmy.Vetayases@oracle.com * obsoleted if there are pending requests on it. Otherwise, 53012683SJimmy.Vetayases@oracle.com * free the vector. The obsoleted vectors get freed after 53112683SJimmy.Vetayases@oracle.com * being serviced. 53212683SJimmy.Vetayases@oracle.com * 53312683SJimmy.Vetayases@oracle.com * Return 1 on being obosoleted and 0 on being freed. 53412683SJimmy.Vetayases@oracle.com */ 53512683SJimmy.Vetayases@oracle.com #define INTR_BUSY(_avp)\ 53612683SJimmy.Vetayases@oracle.com ((((volatile ushort_t)(_avp)->av_flags) &\ 53712683SJimmy.Vetayases@oracle.com (AV_PENTRY_PEND | AV_PENTRY_ONPROC)) != 0) 53812683SJimmy.Vetayases@oracle.com #define LOCAL_WITH_INTR_DISABLED(_cpuid)\ 53912683SJimmy.Vetayases@oracle.com ((_cpuid) == psm_get_cpu_id() && !interrupts_enabled()) 54012683SJimmy.Vetayases@oracle.com static uint64_t dummy_tick; 54112683SJimmy.Vetayases@oracle.com 54212683SJimmy.Vetayases@oracle.com int 54312683SJimmy.Vetayases@oracle.com apix_obsolete_vector(apix_vector_t *vecp) 54412683SJimmy.Vetayases@oracle.com { 54512683SJimmy.Vetayases@oracle.com struct autovec *avp = vecp->v_autovect; 54612683SJimmy.Vetayases@oracle.com int repeats, tries, ipl, busy = 0, cpuid = vecp->v_cpuid; 54712683SJimmy.Vetayases@oracle.com apix_impl_t *apixp = apixs[cpuid]; 54812683SJimmy.Vetayases@oracle.com 54912683SJimmy.Vetayases@oracle.com ASSERT(APIX_CPU_LOCK_HELD(cpuid)); 55012683SJimmy.Vetayases@oracle.com 55112683SJimmy.Vetayases@oracle.com for (avp = vecp->v_autovect; avp != NULL; avp = avp->av_link) { 55212683SJimmy.Vetayases@oracle.com if (avp->av_vector == NULL) 55312683SJimmy.Vetayases@oracle.com continue; 55412683SJimmy.Vetayases@oracle.com 55512683SJimmy.Vetayases@oracle.com if (LOCAL_WITH_INTR_DISABLED(cpuid)) { 55612683SJimmy.Vetayases@oracle.com int bit, index, irr; 55712683SJimmy.Vetayases@oracle.com 55812683SJimmy.Vetayases@oracle.com if (INTR_BUSY(avp)) { 55912683SJimmy.Vetayases@oracle.com busy++; 56012683SJimmy.Vetayases@oracle.com continue; 56112683SJimmy.Vetayases@oracle.com } 56212683SJimmy.Vetayases@oracle.com 56312683SJimmy.Vetayases@oracle.com /* check IRR for pending interrupts */ 56412683SJimmy.Vetayases@oracle.com index = vecp->v_vector / 32; 56512683SJimmy.Vetayases@oracle.com bit = vecp->v_vector % 32; 56612683SJimmy.Vetayases@oracle.com irr = apic_reg_ops->apic_read(APIC_IRR_REG + index); 56712683SJimmy.Vetayases@oracle.com if ((irr & (1 << bit)) != 0) 56812683SJimmy.Vetayases@oracle.com busy++; 56912683SJimmy.Vetayases@oracle.com 57012683SJimmy.Vetayases@oracle.com if (!busy) 57112683SJimmy.Vetayases@oracle.com apix_remove_av(vecp, avp); 57212683SJimmy.Vetayases@oracle.com 57312683SJimmy.Vetayases@oracle.com continue; 57412683SJimmy.Vetayases@oracle.com } 57512683SJimmy.Vetayases@oracle.com 57612683SJimmy.Vetayases@oracle.com repeats = 0; 57712683SJimmy.Vetayases@oracle.com do { 57812683SJimmy.Vetayases@oracle.com repeats++; 57912683SJimmy.Vetayases@oracle.com for (tries = 0; tries < apic_max_reps_clear_pending; 58012683SJimmy.Vetayases@oracle.com tries++) 58112683SJimmy.Vetayases@oracle.com if (!INTR_BUSY(avp)) 58212683SJimmy.Vetayases@oracle.com break; 58312683SJimmy.Vetayases@oracle.com } while (INTR_BUSY(avp) && 58412683SJimmy.Vetayases@oracle.com (repeats < apic_max_reps_clear_pending)); 58512683SJimmy.Vetayases@oracle.com 58612683SJimmy.Vetayases@oracle.com if (INTR_BUSY(avp)) 58712683SJimmy.Vetayases@oracle.com busy++; 58812683SJimmy.Vetayases@oracle.com else { 58912683SJimmy.Vetayases@oracle.com /* 59012683SJimmy.Vetayases@oracle.com * Interrupt is not in pending list or being serviced. 59112683SJimmy.Vetayases@oracle.com * However it might be cached in Local APIC's IRR 59212683SJimmy.Vetayases@oracle.com * register. It's impossible to check another CPU's 59312683SJimmy.Vetayases@oracle.com * IRR register. Then wait till lower levels finish 59412683SJimmy.Vetayases@oracle.com * running. 59512683SJimmy.Vetayases@oracle.com */ 59612683SJimmy.Vetayases@oracle.com for (ipl = 1; ipl < MIN(LOCK_LEVEL, vecp->v_pri); ipl++) 59712683SJimmy.Vetayases@oracle.com apix_wait_till_seen(cpuid, ipl); 59812683SJimmy.Vetayases@oracle.com if (INTR_BUSY(avp)) 59912683SJimmy.Vetayases@oracle.com busy++; 60012683SJimmy.Vetayases@oracle.com } 60112683SJimmy.Vetayases@oracle.com 60212683SJimmy.Vetayases@oracle.com if (!busy) 60312683SJimmy.Vetayases@oracle.com apix_remove_av(vecp, avp); 60412683SJimmy.Vetayases@oracle.com } 60512683SJimmy.Vetayases@oracle.com 60612683SJimmy.Vetayases@oracle.com if (busy) { 60712683SJimmy.Vetayases@oracle.com apix_vector_t *tp = apixp->x_obsoletes; 60812683SJimmy.Vetayases@oracle.com 60912683SJimmy.Vetayases@oracle.com if (vecp->v_state == APIX_STATE_OBSOLETED) 61012683SJimmy.Vetayases@oracle.com return (1); 61112683SJimmy.Vetayases@oracle.com 61212683SJimmy.Vetayases@oracle.com vecp->v_state = APIX_STATE_OBSOLETED; 61312683SJimmy.Vetayases@oracle.com vecp->v_next = NULL; 61412683SJimmy.Vetayases@oracle.com if (tp == NULL) 61512683SJimmy.Vetayases@oracle.com apixp->x_obsoletes = vecp; 61612683SJimmy.Vetayases@oracle.com else { 61712683SJimmy.Vetayases@oracle.com while (tp->v_next != NULL) 61812683SJimmy.Vetayases@oracle.com tp = tp->v_next; 61912683SJimmy.Vetayases@oracle.com tp->v_next = vecp; 62012683SJimmy.Vetayases@oracle.com } 62112683SJimmy.Vetayases@oracle.com return (1); 62212683SJimmy.Vetayases@oracle.com } 62312683SJimmy.Vetayases@oracle.com 62412683SJimmy.Vetayases@oracle.com /* interrupt is not busy */ 62512683SJimmy.Vetayases@oracle.com if (vecp->v_state == APIX_STATE_OBSOLETED) { 62612683SJimmy.Vetayases@oracle.com /* remove from obsoleted list */ 62712683SJimmy.Vetayases@oracle.com apixp->x_obsoletes = vecp->v_next; 62812683SJimmy.Vetayases@oracle.com vecp->v_next = NULL; 62912683SJimmy.Vetayases@oracle.com } 63012683SJimmy.Vetayases@oracle.com apix_cleanup_vector(vecp); 63112683SJimmy.Vetayases@oracle.com return (0); 63212683SJimmy.Vetayases@oracle.com } 63312683SJimmy.Vetayases@oracle.com 63412683SJimmy.Vetayases@oracle.com /* 63512683SJimmy.Vetayases@oracle.com * Duplicate number of continuous vectors to specified target vectors. 63612683SJimmy.Vetayases@oracle.com */ 63712683SJimmy.Vetayases@oracle.com static void 63812683SJimmy.Vetayases@oracle.com apix_dup_vectors(apix_vector_t *oldp, apix_vector_t *newp, int count) 63912683SJimmy.Vetayases@oracle.com { 64012683SJimmy.Vetayases@oracle.com struct autovec *avp; 64112683SJimmy.Vetayases@oracle.com apix_vector_t *fromp, *top; 64212683SJimmy.Vetayases@oracle.com processorid_t oldcpu = oldp->v_cpuid, newcpu = newp->v_cpuid; 64312683SJimmy.Vetayases@oracle.com uchar_t oldvec = oldp->v_vector, newvec = newp->v_vector; 64412683SJimmy.Vetayases@oracle.com int i, inum; 64512683SJimmy.Vetayases@oracle.com 64612683SJimmy.Vetayases@oracle.com ASSERT(oldp->v_type != APIX_TYPE_IPI); 64712683SJimmy.Vetayases@oracle.com 64812683SJimmy.Vetayases@oracle.com for (i = 0; i < count; i++) { 64912683SJimmy.Vetayases@oracle.com fromp = xv_vector(oldcpu, oldvec + i); 65012683SJimmy.Vetayases@oracle.com top = xv_vector(newcpu, newvec + i); 65112683SJimmy.Vetayases@oracle.com ASSERT(fromp != NULL && top != NULL); 65212683SJimmy.Vetayases@oracle.com 65312683SJimmy.Vetayases@oracle.com /* copy over original one */ 65412683SJimmy.Vetayases@oracle.com top->v_state = fromp->v_state; 65512683SJimmy.Vetayases@oracle.com top->v_type = fromp->v_type; 65612683SJimmy.Vetayases@oracle.com top->v_bound_cpuid = fromp->v_bound_cpuid; 65712683SJimmy.Vetayases@oracle.com top->v_inum = fromp->v_inum; 65812683SJimmy.Vetayases@oracle.com top->v_flags = fromp->v_flags; 65912683SJimmy.Vetayases@oracle.com top->v_intrmap_private = fromp->v_intrmap_private; 66012683SJimmy.Vetayases@oracle.com 66112683SJimmy.Vetayases@oracle.com for (avp = fromp->v_autovect; avp != NULL; avp = avp->av_link) { 66212683SJimmy.Vetayases@oracle.com if (avp->av_vector == NULL) 66312683SJimmy.Vetayases@oracle.com continue; 66412683SJimmy.Vetayases@oracle.com 66512683SJimmy.Vetayases@oracle.com apix_insert_av(top, avp->av_intr_id, avp->av_vector, 66612683SJimmy.Vetayases@oracle.com avp->av_intarg1, avp->av_intarg2, avp->av_ticksp, 66712683SJimmy.Vetayases@oracle.com avp->av_prilevel, avp->av_dip); 66812683SJimmy.Vetayases@oracle.com 66912683SJimmy.Vetayases@oracle.com if (fromp->v_type == APIX_TYPE_FIXED && 67012683SJimmy.Vetayases@oracle.com avp->av_dip != NULL) { 67112683SJimmy.Vetayases@oracle.com inum = GET_INTR_INUM(avp->av_intr_id); 67212683SJimmy.Vetayases@oracle.com apix_set_dev_map(top, avp->av_dip, inum); 67312683SJimmy.Vetayases@oracle.com } 67412683SJimmy.Vetayases@oracle.com } 67512683SJimmy.Vetayases@oracle.com 67612683SJimmy.Vetayases@oracle.com if (DDI_INTR_IS_MSI_OR_MSIX(fromp->v_type) && 67712683SJimmy.Vetayases@oracle.com fromp->v_devp != NULL) 67812683SJimmy.Vetayases@oracle.com apix_set_dev_map(top, fromp->v_devp->dv_dip, 67912683SJimmy.Vetayases@oracle.com fromp->v_devp->dv_inum); 68012683SJimmy.Vetayases@oracle.com } 68112683SJimmy.Vetayases@oracle.com } 68212683SJimmy.Vetayases@oracle.com 68312683SJimmy.Vetayases@oracle.com static apix_vector_t * 68412683SJimmy.Vetayases@oracle.com apix_init_vector(processorid_t cpuid, uchar_t vector) 68512683SJimmy.Vetayases@oracle.com { 68612683SJimmy.Vetayases@oracle.com apix_impl_t *apixp = apixs[cpuid]; 68712683SJimmy.Vetayases@oracle.com apix_vector_t *vecp = apixp->x_vectbl[vector]; 68812683SJimmy.Vetayases@oracle.com 68912683SJimmy.Vetayases@oracle.com ASSERT(IS_VECT_FREE(vecp)); 69012683SJimmy.Vetayases@oracle.com 69112683SJimmy.Vetayases@oracle.com if (vecp == NULL) { 69212683SJimmy.Vetayases@oracle.com vecp = kmem_zalloc(sizeof (apix_vector_t), KM_NOSLEEP); 69312683SJimmy.Vetayases@oracle.com if (vecp == NULL) { 69412683SJimmy.Vetayases@oracle.com cmn_err(CE_WARN, "apix: no memory to allocate vector"); 69512683SJimmy.Vetayases@oracle.com return (NULL); 69612683SJimmy.Vetayases@oracle.com } 69712683SJimmy.Vetayases@oracle.com apixp->x_vectbl[vector] = vecp; 69812683SJimmy.Vetayases@oracle.com } 69912683SJimmy.Vetayases@oracle.com vecp->v_state = APIX_STATE_ALLOCED; 70012683SJimmy.Vetayases@oracle.com vecp->v_cpuid = vecp->v_bound_cpuid = cpuid; 70112683SJimmy.Vetayases@oracle.com vecp->v_vector = vector; 70212683SJimmy.Vetayases@oracle.com 70312683SJimmy.Vetayases@oracle.com return (vecp); 70412683SJimmy.Vetayases@oracle.com } 70512683SJimmy.Vetayases@oracle.com 70612683SJimmy.Vetayases@oracle.com static void 70712683SJimmy.Vetayases@oracle.com apix_cleanup_vector(apix_vector_t *vecp) 70812683SJimmy.Vetayases@oracle.com { 70912683SJimmy.Vetayases@oracle.com ASSERT(vecp->v_share == 0); 71012683SJimmy.Vetayases@oracle.com vecp->v_bound_cpuid = IRQ_UNINIT; 71112683SJimmy.Vetayases@oracle.com vecp->v_state = APIX_STATE_FREED; 71212683SJimmy.Vetayases@oracle.com vecp->v_type = 0; 71312683SJimmy.Vetayases@oracle.com vecp->v_flags = 0; 71412683SJimmy.Vetayases@oracle.com vecp->v_busy = 0; 715*12752SPrasad.Singamsetty@Sun.COM vecp->v_intrmap_private = NULL; 71612683SJimmy.Vetayases@oracle.com } 71712683SJimmy.Vetayases@oracle.com 71812683SJimmy.Vetayases@oracle.com static void 71912683SJimmy.Vetayases@oracle.com apix_dprint_vector(apix_vector_t *vecp, dev_info_t *dip, int count) 72012683SJimmy.Vetayases@oracle.com { 72112683SJimmy.Vetayases@oracle.com #ifdef DEBUG 72212683SJimmy.Vetayases@oracle.com major_t major; 72312683SJimmy.Vetayases@oracle.com char *name, *drv_name; 72412683SJimmy.Vetayases@oracle.com int instance, len, t_len; 72512683SJimmy.Vetayases@oracle.com char mesg[1024] = "apix: "; 72612683SJimmy.Vetayases@oracle.com 72712683SJimmy.Vetayases@oracle.com t_len = sizeof (mesg); 72812683SJimmy.Vetayases@oracle.com len = strlen(mesg); 72912683SJimmy.Vetayases@oracle.com if (dip != NULL) { 73012683SJimmy.Vetayases@oracle.com name = ddi_get_name(dip); 73112683SJimmy.Vetayases@oracle.com major = ddi_name_to_major(name); 73212683SJimmy.Vetayases@oracle.com drv_name = ddi_major_to_name(major); 73312683SJimmy.Vetayases@oracle.com instance = ddi_get_instance(dip); 73412683SJimmy.Vetayases@oracle.com (void) snprintf(mesg + len, t_len - len, "%s (%s) instance %d ", 73512683SJimmy.Vetayases@oracle.com name, drv_name, instance); 73612683SJimmy.Vetayases@oracle.com } 73712683SJimmy.Vetayases@oracle.com len = strlen(mesg); 73812683SJimmy.Vetayases@oracle.com 73912683SJimmy.Vetayases@oracle.com switch (vecp->v_type) { 74012683SJimmy.Vetayases@oracle.com case APIX_TYPE_FIXED: 74112683SJimmy.Vetayases@oracle.com (void) snprintf(mesg + len, t_len - len, "irqno %d", 74212683SJimmy.Vetayases@oracle.com vecp->v_inum); 74312683SJimmy.Vetayases@oracle.com break; 74412683SJimmy.Vetayases@oracle.com case APIX_TYPE_MSI: 74512683SJimmy.Vetayases@oracle.com (void) snprintf(mesg + len, t_len - len, 74612683SJimmy.Vetayases@oracle.com "msi inum %d (count %d)", vecp->v_inum, count); 74712683SJimmy.Vetayases@oracle.com break; 74812683SJimmy.Vetayases@oracle.com case APIX_TYPE_MSIX: 74912683SJimmy.Vetayases@oracle.com (void) snprintf(mesg + len, t_len - len, "msi-x inum %d", 75012683SJimmy.Vetayases@oracle.com vecp->v_inum); 75112683SJimmy.Vetayases@oracle.com break; 75212683SJimmy.Vetayases@oracle.com default: 75312683SJimmy.Vetayases@oracle.com break; 75412683SJimmy.Vetayases@oracle.com 75512683SJimmy.Vetayases@oracle.com } 75612683SJimmy.Vetayases@oracle.com 75712683SJimmy.Vetayases@oracle.com APIC_VERBOSE(ALLOC, (CE_CONT, "%s allocated with vector 0x%x on " 75812683SJimmy.Vetayases@oracle.com "cpu %d\n", mesg, vecp->v_vector, vecp->v_cpuid)); 75912683SJimmy.Vetayases@oracle.com #endif /* DEBUG */ 76012683SJimmy.Vetayases@oracle.com } 76112683SJimmy.Vetayases@oracle.com 76212683SJimmy.Vetayases@oracle.com /* 76312683SJimmy.Vetayases@oracle.com * Operations on avintr 76412683SJimmy.Vetayases@oracle.com */ 76512683SJimmy.Vetayases@oracle.com 76612683SJimmy.Vetayases@oracle.com #define INIT_AUTOVEC(p, intr_id, f, arg1, arg2, ticksp, ipl, dip) \ 76712683SJimmy.Vetayases@oracle.com do { \ 76812683SJimmy.Vetayases@oracle.com (p)->av_intr_id = intr_id; \ 76912683SJimmy.Vetayases@oracle.com (p)->av_vector = f; \ 77012683SJimmy.Vetayases@oracle.com (p)->av_intarg1 = arg1; \ 77112683SJimmy.Vetayases@oracle.com (p)->av_intarg2 = arg2; \ 77212683SJimmy.Vetayases@oracle.com (p)->av_ticksp = ticksp; \ 77312683SJimmy.Vetayases@oracle.com (p)->av_prilevel = ipl; \ 77412683SJimmy.Vetayases@oracle.com (p)->av_dip = dip; \ 77512683SJimmy.Vetayases@oracle.com (p)->av_flags = 0; \ 77612683SJimmy.Vetayases@oracle.com _NOTE(CONSTCOND)} while (0) 77712683SJimmy.Vetayases@oracle.com 77812683SJimmy.Vetayases@oracle.com /* 77912683SJimmy.Vetayases@oracle.com * Insert an interrupt service routine into chain by its priority from 78012683SJimmy.Vetayases@oracle.com * high to low 78112683SJimmy.Vetayases@oracle.com */ 78212683SJimmy.Vetayases@oracle.com static void 78312683SJimmy.Vetayases@oracle.com apix_insert_av(apix_vector_t *vecp, void *intr_id, avfunc f, caddr_t arg1, 78412683SJimmy.Vetayases@oracle.com caddr_t arg2, uint64_t *ticksp, int ipl, dev_info_t *dip) 78512683SJimmy.Vetayases@oracle.com { 78612683SJimmy.Vetayases@oracle.com struct autovec *p, *prep, *mem; 78712683SJimmy.Vetayases@oracle.com 78812683SJimmy.Vetayases@oracle.com APIC_VERBOSE(INTR, (CE_CONT, "apix_insert_av: dip %p, vector 0x%x, " 78912683SJimmy.Vetayases@oracle.com "cpu %d\n", (void *)dip, vecp->v_vector, vecp->v_cpuid)); 79012683SJimmy.Vetayases@oracle.com 79112683SJimmy.Vetayases@oracle.com mem = kmem_zalloc(sizeof (struct autovec), KM_SLEEP); 79212683SJimmy.Vetayases@oracle.com INIT_AUTOVEC(mem, intr_id, f, arg1, arg2, ticksp, ipl, dip); 79312683SJimmy.Vetayases@oracle.com if (vecp->v_type == APIX_TYPE_FIXED && apic_level_intr[vecp->v_inum]) 79412683SJimmy.Vetayases@oracle.com mem->av_flags |= AV_PENTRY_LEVEL; 79512683SJimmy.Vetayases@oracle.com 79612683SJimmy.Vetayases@oracle.com vecp->v_share++; 79712683SJimmy.Vetayases@oracle.com vecp->v_pri = (ipl > vecp->v_pri) ? ipl : vecp->v_pri; 79812683SJimmy.Vetayases@oracle.com if (vecp->v_autovect == NULL) { /* Nothing on list - put it at head */ 79912683SJimmy.Vetayases@oracle.com vecp->v_autovect = mem; 80012683SJimmy.Vetayases@oracle.com return; 80112683SJimmy.Vetayases@oracle.com } 80212683SJimmy.Vetayases@oracle.com 80312683SJimmy.Vetayases@oracle.com if (DDI_INTR_IS_MSI_OR_MSIX(vecp->v_type)) { /* MSI/X */ 80412683SJimmy.Vetayases@oracle.com ASSERT(vecp->v_share == 1); /* No sharing for MSI/X */ 80512683SJimmy.Vetayases@oracle.com 80612683SJimmy.Vetayases@oracle.com INIT_AUTOVEC(vecp->v_autovect, intr_id, f, arg1, arg2, ticksp, 80712683SJimmy.Vetayases@oracle.com ipl, dip); 80812683SJimmy.Vetayases@oracle.com prep = vecp->v_autovect->av_link; 80912683SJimmy.Vetayases@oracle.com vecp->v_autovect->av_link = NULL; 81012683SJimmy.Vetayases@oracle.com 81112683SJimmy.Vetayases@oracle.com /* Free the following autovect chain */ 81212683SJimmy.Vetayases@oracle.com while (prep != NULL) { 81312683SJimmy.Vetayases@oracle.com ASSERT(prep->av_vector == NULL); 81412683SJimmy.Vetayases@oracle.com 81512683SJimmy.Vetayases@oracle.com p = prep; 81612683SJimmy.Vetayases@oracle.com prep = prep->av_link; 81712683SJimmy.Vetayases@oracle.com kmem_free(p, sizeof (struct autovec)); 81812683SJimmy.Vetayases@oracle.com } 81912683SJimmy.Vetayases@oracle.com 82012683SJimmy.Vetayases@oracle.com kmem_free(mem, sizeof (struct autovec)); 82112683SJimmy.Vetayases@oracle.com return; 82212683SJimmy.Vetayases@oracle.com } 82312683SJimmy.Vetayases@oracle.com 82412683SJimmy.Vetayases@oracle.com /* find where it goes in list */ 82512683SJimmy.Vetayases@oracle.com prep = NULL; 82612683SJimmy.Vetayases@oracle.com for (p = vecp->v_autovect; p != NULL; p = p->av_link) { 82712683SJimmy.Vetayases@oracle.com if (p->av_vector && p->av_prilevel <= ipl) 82812683SJimmy.Vetayases@oracle.com break; 82912683SJimmy.Vetayases@oracle.com prep = p; 83012683SJimmy.Vetayases@oracle.com } 83112683SJimmy.Vetayases@oracle.com if (prep != NULL) { 83212683SJimmy.Vetayases@oracle.com if (prep->av_vector == NULL) { /* freed struct available */ 83312683SJimmy.Vetayases@oracle.com INIT_AUTOVEC(prep, intr_id, f, arg1, arg2, 83412683SJimmy.Vetayases@oracle.com ticksp, ipl, dip); 83512683SJimmy.Vetayases@oracle.com prep->av_flags = mem->av_flags; 83612683SJimmy.Vetayases@oracle.com kmem_free(mem, sizeof (struct autovec)); 83712683SJimmy.Vetayases@oracle.com return; 83812683SJimmy.Vetayases@oracle.com } 83912683SJimmy.Vetayases@oracle.com 84012683SJimmy.Vetayases@oracle.com mem->av_link = prep->av_link; 84112683SJimmy.Vetayases@oracle.com prep->av_link = mem; 84212683SJimmy.Vetayases@oracle.com } else { 84312683SJimmy.Vetayases@oracle.com /* insert new intpt at beginning of chain */ 84412683SJimmy.Vetayases@oracle.com mem->av_link = vecp->v_autovect; 84512683SJimmy.Vetayases@oracle.com vecp->v_autovect = mem; 84612683SJimmy.Vetayases@oracle.com } 84712683SJimmy.Vetayases@oracle.com } 84812683SJimmy.Vetayases@oracle.com 84912683SJimmy.Vetayases@oracle.com /* 85012683SJimmy.Vetayases@oracle.com * After having made a change to an autovector list, wait until we have 85112683SJimmy.Vetayases@oracle.com * seen specified cpu not executing an interrupt at that level--so we 85212683SJimmy.Vetayases@oracle.com * know our change has taken effect completely (no old state in registers, 85312683SJimmy.Vetayases@oracle.com * etc). 85412683SJimmy.Vetayases@oracle.com */ 85512683SJimmy.Vetayases@oracle.com #define APIX_CPU_ENABLED(_cp) \ 85612683SJimmy.Vetayases@oracle.com (quiesce_active == 0 && \ 85712683SJimmy.Vetayases@oracle.com (((_cp)->cpu_flags & (CPU_QUIESCED|CPU_OFFLINE)) == 0)) 85812683SJimmy.Vetayases@oracle.com 85912683SJimmy.Vetayases@oracle.com static void 86012683SJimmy.Vetayases@oracle.com apix_wait_till_seen(processorid_t cpuid, int ipl) 86112683SJimmy.Vetayases@oracle.com { 86212683SJimmy.Vetayases@oracle.com struct cpu *cp = cpu[cpuid]; 86312683SJimmy.Vetayases@oracle.com 86412683SJimmy.Vetayases@oracle.com if (cp == NULL || LOCAL_WITH_INTR_DISABLED(cpuid)) 86512683SJimmy.Vetayases@oracle.com return; 86612683SJimmy.Vetayases@oracle.com 86712683SJimmy.Vetayases@oracle.com /* 86812683SJimmy.Vetayases@oracle.com * Don't wait if the CPU is quiesced or offlined. This can happen 86912683SJimmy.Vetayases@oracle.com * when a CPU is running pause thread but hardware triggered an 87012683SJimmy.Vetayases@oracle.com * interrupt and the interrupt gets queued. 87112683SJimmy.Vetayases@oracle.com */ 87212683SJimmy.Vetayases@oracle.com for (;;) { 87312683SJimmy.Vetayases@oracle.com if (!INTR_ACTIVE((volatile struct cpu *)cpu[cpuid], ipl) && 87412683SJimmy.Vetayases@oracle.com (!APIX_CPU_ENABLED(cp) || 87512683SJimmy.Vetayases@oracle.com !INTR_PENDING((volatile apix_impl_t *)apixs[cpuid], ipl))) 87612683SJimmy.Vetayases@oracle.com return; 87712683SJimmy.Vetayases@oracle.com } 87812683SJimmy.Vetayases@oracle.com } 87912683SJimmy.Vetayases@oracle.com 88012683SJimmy.Vetayases@oracle.com static void 88112683SJimmy.Vetayases@oracle.com apix_remove_av(apix_vector_t *vecp, struct autovec *target) 88212683SJimmy.Vetayases@oracle.com { 88312683SJimmy.Vetayases@oracle.com int hi_pri = 0; 88412683SJimmy.Vetayases@oracle.com struct autovec *p; 88512683SJimmy.Vetayases@oracle.com 88612683SJimmy.Vetayases@oracle.com if (target == NULL) 88712683SJimmy.Vetayases@oracle.com return; 88812683SJimmy.Vetayases@oracle.com 88912683SJimmy.Vetayases@oracle.com APIC_VERBOSE(INTR, (CE_CONT, "apix_remove_av: dip %p, vector 0x%x, " 89012683SJimmy.Vetayases@oracle.com "cpu %d\n", (void *)target->av_dip, vecp->v_vector, vecp->v_cpuid)); 89112683SJimmy.Vetayases@oracle.com 89212683SJimmy.Vetayases@oracle.com for (p = vecp->v_autovect; p; p = p->av_link) { 89312683SJimmy.Vetayases@oracle.com if (p == target || p->av_vector == NULL) 89412683SJimmy.Vetayases@oracle.com continue; 89512683SJimmy.Vetayases@oracle.com hi_pri = (p->av_prilevel > hi_pri) ? p->av_prilevel : hi_pri; 89612683SJimmy.Vetayases@oracle.com } 89712683SJimmy.Vetayases@oracle.com 89812683SJimmy.Vetayases@oracle.com vecp->v_share--; 89912683SJimmy.Vetayases@oracle.com vecp->v_pri = hi_pri; 90012683SJimmy.Vetayases@oracle.com 90112683SJimmy.Vetayases@oracle.com /* 90212683SJimmy.Vetayases@oracle.com * This drops the handler from the chain, it can no longer be called. 90312683SJimmy.Vetayases@oracle.com * However, there is no guarantee that the handler is not currently 90412683SJimmy.Vetayases@oracle.com * still executing. 90512683SJimmy.Vetayases@oracle.com */ 90612683SJimmy.Vetayases@oracle.com target->av_vector = NULL; 90712683SJimmy.Vetayases@oracle.com /* 90812683SJimmy.Vetayases@oracle.com * There is a race where we could be just about to pick up the ticksp 90912683SJimmy.Vetayases@oracle.com * pointer to increment it after returning from the service routine 91012683SJimmy.Vetayases@oracle.com * in av_dispatch_autovect. Rather than NULL it out let's just point 91112683SJimmy.Vetayases@oracle.com * it off to something safe so that any final tick update attempt 91212683SJimmy.Vetayases@oracle.com * won't fault. 91312683SJimmy.Vetayases@oracle.com */ 91412683SJimmy.Vetayases@oracle.com target->av_ticksp = &dummy_tick; 91512683SJimmy.Vetayases@oracle.com apix_wait_till_seen(vecp->v_cpuid, target->av_prilevel); 91612683SJimmy.Vetayases@oracle.com } 91712683SJimmy.Vetayases@oracle.com 91812683SJimmy.Vetayases@oracle.com static struct autovec * 91912683SJimmy.Vetayases@oracle.com apix_find_av(apix_vector_t *vecp, void *intr_id, avfunc f) 92012683SJimmy.Vetayases@oracle.com { 92112683SJimmy.Vetayases@oracle.com struct autovec *p; 92212683SJimmy.Vetayases@oracle.com 92312683SJimmy.Vetayases@oracle.com for (p = vecp->v_autovect; p; p = p->av_link) { 92412683SJimmy.Vetayases@oracle.com if ((p->av_vector == f) && (p->av_intr_id == intr_id)) { 92512683SJimmy.Vetayases@oracle.com /* found the handler */ 92612683SJimmy.Vetayases@oracle.com return (p); 92712683SJimmy.Vetayases@oracle.com } 92812683SJimmy.Vetayases@oracle.com } 92912683SJimmy.Vetayases@oracle.com 93012683SJimmy.Vetayases@oracle.com return (NULL); 93112683SJimmy.Vetayases@oracle.com } 93212683SJimmy.Vetayases@oracle.com 93312683SJimmy.Vetayases@oracle.com static apix_vector_t * 93412683SJimmy.Vetayases@oracle.com apix_find_vector_by_avintr(void *intr_id, avfunc f) 93512683SJimmy.Vetayases@oracle.com { 93612683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 93712683SJimmy.Vetayases@oracle.com processorid_t n; 93812683SJimmy.Vetayases@oracle.com uchar_t v; 93912683SJimmy.Vetayases@oracle.com 94012683SJimmy.Vetayases@oracle.com for (n = 0; n < apic_nproc; n++) { 94112683SJimmy.Vetayases@oracle.com if (!apix_is_cpu_enabled(n)) 94212683SJimmy.Vetayases@oracle.com continue; 94312683SJimmy.Vetayases@oracle.com 94412683SJimmy.Vetayases@oracle.com for (v = APIX_AVINTR_MIN; v <= APIX_AVINTR_MIN; v++) { 94512683SJimmy.Vetayases@oracle.com vecp = xv_vector(n, v); 94612683SJimmy.Vetayases@oracle.com if (vecp == NULL || 94712683SJimmy.Vetayases@oracle.com vecp->v_state <= APIX_STATE_OBSOLETED) 94812683SJimmy.Vetayases@oracle.com continue; 94912683SJimmy.Vetayases@oracle.com 95012683SJimmy.Vetayases@oracle.com if (apix_find_av(vecp, intr_id, f) != NULL) 95112683SJimmy.Vetayases@oracle.com return (vecp); 95212683SJimmy.Vetayases@oracle.com } 95312683SJimmy.Vetayases@oracle.com } 95412683SJimmy.Vetayases@oracle.com 95512683SJimmy.Vetayases@oracle.com return (NULL); 95612683SJimmy.Vetayases@oracle.com } 95712683SJimmy.Vetayases@oracle.com 95812683SJimmy.Vetayases@oracle.com /* 95912683SJimmy.Vetayases@oracle.com * Add interrupt service routine. 96012683SJimmy.Vetayases@oracle.com * 96112683SJimmy.Vetayases@oracle.com * For legacy interrupts (HPET timer, ACPI SCI), the vector is actually 96212683SJimmy.Vetayases@oracle.com * IRQ no. A vector is then allocated. Otherwise, the vector is already 96312683SJimmy.Vetayases@oracle.com * allocated. The input argument virt_vect is virtual vector of format 96412683SJimmy.Vetayases@oracle.com * APIX_VIRTVEC_VECTOR(cpuid, vector). 96512683SJimmy.Vetayases@oracle.com * 96612683SJimmy.Vetayases@oracle.com * Return 1 on success, 0 on failure. 96712683SJimmy.Vetayases@oracle.com */ 96812683SJimmy.Vetayases@oracle.com int 96912683SJimmy.Vetayases@oracle.com apix_add_avintr(void *intr_id, int ipl, avfunc xxintr, char *name, 97012683SJimmy.Vetayases@oracle.com int virt_vect, caddr_t arg1, caddr_t arg2, uint64_t *ticksp, 97112683SJimmy.Vetayases@oracle.com dev_info_t *dip) 97212683SJimmy.Vetayases@oracle.com { 97312683SJimmy.Vetayases@oracle.com int cpuid; 97412683SJimmy.Vetayases@oracle.com uchar_t v = (uchar_t)APIX_VIRTVEC_VECTOR(virt_vect); 97512683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 97612683SJimmy.Vetayases@oracle.com 97712683SJimmy.Vetayases@oracle.com if (xxintr == NULL) { 97812683SJimmy.Vetayases@oracle.com cmn_err(CE_WARN, "Attempt to add null for %s " 97912683SJimmy.Vetayases@oracle.com "on vector 0x%x,0x%x", name, 98012683SJimmy.Vetayases@oracle.com APIX_VIRTVEC_CPU(virt_vect), 98112683SJimmy.Vetayases@oracle.com APIX_VIRTVEC_VECTOR(virt_vect)); 98212683SJimmy.Vetayases@oracle.com return (0); 98312683SJimmy.Vetayases@oracle.com } 98412683SJimmy.Vetayases@oracle.com 98512683SJimmy.Vetayases@oracle.com if (v >= APIX_IPI_MIN) /* IPIs */ 98612683SJimmy.Vetayases@oracle.com return (apix_add_ipi(ipl, xxintr, name, v, arg1, arg2)); 98712683SJimmy.Vetayases@oracle.com 98812683SJimmy.Vetayases@oracle.com if (!APIX_IS_VIRTVEC(virt_vect)) { /* got irq */ 98912683SJimmy.Vetayases@oracle.com int irqno = virt_vect; 99012683SJimmy.Vetayases@oracle.com int inum = GET_INTR_INUM(intr_id); 99112683SJimmy.Vetayases@oracle.com 99212683SJimmy.Vetayases@oracle.com /* 99312683SJimmy.Vetayases@oracle.com * Senarios include: 99412683SJimmy.Vetayases@oracle.com * a. add_avintr() is called before irqp initialized (legacy) 99512683SJimmy.Vetayases@oracle.com * b. irqp is initialized, vector is not allocated (fixed) 99612683SJimmy.Vetayases@oracle.com * c. irqp is initialized, vector is allocated (fixed & shared) 99712683SJimmy.Vetayases@oracle.com */ 99812683SJimmy.Vetayases@oracle.com if ((vecp = apix_alloc_intx(dip, inum, irqno)) == NULL) 99912683SJimmy.Vetayases@oracle.com return (0); 100012683SJimmy.Vetayases@oracle.com 100112683SJimmy.Vetayases@oracle.com cpuid = vecp->v_cpuid; 100212683SJimmy.Vetayases@oracle.com v = vecp->v_vector; 100312683SJimmy.Vetayases@oracle.com virt_vect = APIX_VIRTVECTOR(cpuid, v); 100412683SJimmy.Vetayases@oracle.com } else { /* got virtual vector */ 100512683SJimmy.Vetayases@oracle.com cpuid = APIX_VIRTVEC_CPU(virt_vect); 100612683SJimmy.Vetayases@oracle.com vecp = xv_vector(cpuid, v); 100712683SJimmy.Vetayases@oracle.com ASSERT(vecp != NULL); 100812683SJimmy.Vetayases@oracle.com } 100912683SJimmy.Vetayases@oracle.com 101012683SJimmy.Vetayases@oracle.com lock_set(&apix_lock); 101112683SJimmy.Vetayases@oracle.com if (vecp->v_state <= APIX_STATE_OBSOLETED) { 101212683SJimmy.Vetayases@oracle.com vecp = NULL; 101312683SJimmy.Vetayases@oracle.com 101412683SJimmy.Vetayases@oracle.com /* 101512683SJimmy.Vetayases@oracle.com * Basically the allocated but not enabled interrupts 101612683SJimmy.Vetayases@oracle.com * will not get re-targeted. But MSIs in allocated state 101712683SJimmy.Vetayases@oracle.com * could be re-targeted due to group re-targeting. 101812683SJimmy.Vetayases@oracle.com */ 101912683SJimmy.Vetayases@oracle.com if (intr_id != NULL && dip != NULL) { 102012683SJimmy.Vetayases@oracle.com ddi_intr_handle_impl_t *hdlp = intr_id; 102112683SJimmy.Vetayases@oracle.com vecp = apix_get_dev_map(dip, hdlp->ih_inum, 102212683SJimmy.Vetayases@oracle.com hdlp->ih_type); 102312683SJimmy.Vetayases@oracle.com ASSERT(vecp->v_state == APIX_STATE_ALLOCED); 102412683SJimmy.Vetayases@oracle.com } 102512683SJimmy.Vetayases@oracle.com if (vecp == NULL) { 102612683SJimmy.Vetayases@oracle.com lock_clear(&apix_lock); 102712683SJimmy.Vetayases@oracle.com cmn_err(CE_WARN, "Invalid interrupt 0x%x,0x%x " 102812683SJimmy.Vetayases@oracle.com " for %p to add", cpuid, v, intr_id); 102912683SJimmy.Vetayases@oracle.com return (0); 103012683SJimmy.Vetayases@oracle.com } 103112683SJimmy.Vetayases@oracle.com cpuid = vecp->v_cpuid; 103212683SJimmy.Vetayases@oracle.com virt_vect = APIX_VIRTVECTOR(cpuid, vecp->v_vector); 103312683SJimmy.Vetayases@oracle.com } 103412683SJimmy.Vetayases@oracle.com 103512683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(cpuid); 103612683SJimmy.Vetayases@oracle.com apix_insert_av(vecp, intr_id, xxintr, arg1, arg2, ticksp, ipl, dip); 103712683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(cpuid); 103812683SJimmy.Vetayases@oracle.com 103912683SJimmy.Vetayases@oracle.com (void) apix_addspl(virt_vect, ipl, 0, 0); 104012683SJimmy.Vetayases@oracle.com 104112683SJimmy.Vetayases@oracle.com lock_clear(&apix_lock); 104212683SJimmy.Vetayases@oracle.com 104312683SJimmy.Vetayases@oracle.com return (1); 104412683SJimmy.Vetayases@oracle.com } 104512683SJimmy.Vetayases@oracle.com 104612683SJimmy.Vetayases@oracle.com /* 104712683SJimmy.Vetayases@oracle.com * Remove avintr 104812683SJimmy.Vetayases@oracle.com * 104912683SJimmy.Vetayases@oracle.com * For fixed, if it's the last one of shared interrupts, free the vector. 105012683SJimmy.Vetayases@oracle.com * For msi/x, only disable the interrupt but not free the vector, which 105112683SJimmy.Vetayases@oracle.com * is freed by PSM_XXX_FREE_XXX. 105212683SJimmy.Vetayases@oracle.com */ 105312683SJimmy.Vetayases@oracle.com void 105412683SJimmy.Vetayases@oracle.com apix_rem_avintr(void *intr_id, int ipl, avfunc xxintr, int virt_vect) 105512683SJimmy.Vetayases@oracle.com { 105612683SJimmy.Vetayases@oracle.com avfunc f; 105712683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 105812683SJimmy.Vetayases@oracle.com struct autovec *avp; 105912683SJimmy.Vetayases@oracle.com processorid_t cpuid; 106012683SJimmy.Vetayases@oracle.com 106112683SJimmy.Vetayases@oracle.com if ((f = xxintr) == NULL) 106212683SJimmy.Vetayases@oracle.com return; 106312683SJimmy.Vetayases@oracle.com 106412683SJimmy.Vetayases@oracle.com lock_set(&apix_lock); 106512683SJimmy.Vetayases@oracle.com 106612683SJimmy.Vetayases@oracle.com if (!APIX_IS_VIRTVEC(virt_vect)) { /* got irq */ 106712683SJimmy.Vetayases@oracle.com vecp = apix_intx_get_vector(virt_vect); 106812683SJimmy.Vetayases@oracle.com virt_vect = APIX_VIRTVECTOR(vecp->v_cpuid, vecp->v_vector); 106912683SJimmy.Vetayases@oracle.com } else /* got virtual vector */ 107012683SJimmy.Vetayases@oracle.com vecp = xv_vector(APIX_VIRTVEC_CPU(virt_vect), 107112683SJimmy.Vetayases@oracle.com APIX_VIRTVEC_VECTOR(virt_vect)); 107212683SJimmy.Vetayases@oracle.com 107312683SJimmy.Vetayases@oracle.com if (vecp == NULL) { 107412683SJimmy.Vetayases@oracle.com lock_clear(&apix_lock); 107512683SJimmy.Vetayases@oracle.com cmn_err(CE_CONT, "Invalid interrupt 0x%x,0x%x to remove", 107612683SJimmy.Vetayases@oracle.com APIX_VIRTVEC_CPU(virt_vect), 107712683SJimmy.Vetayases@oracle.com APIX_VIRTVEC_VECTOR(virt_vect)); 107812683SJimmy.Vetayases@oracle.com return; 107912683SJimmy.Vetayases@oracle.com } 108012683SJimmy.Vetayases@oracle.com 108112683SJimmy.Vetayases@oracle.com if (vecp->v_state <= APIX_STATE_OBSOLETED || 108212683SJimmy.Vetayases@oracle.com ((avp = apix_find_av(vecp, intr_id, f)) == NULL)) { 108312683SJimmy.Vetayases@oracle.com /* 108412683SJimmy.Vetayases@oracle.com * It's possible that the interrupt is rebound to a 108512683SJimmy.Vetayases@oracle.com * different cpu before rem_avintr() is called. Search 108612683SJimmy.Vetayases@oracle.com * through all vectors once it happens. 108712683SJimmy.Vetayases@oracle.com */ 108812683SJimmy.Vetayases@oracle.com if ((vecp = apix_find_vector_by_avintr(intr_id, f)) 108912683SJimmy.Vetayases@oracle.com == NULL) { 109012683SJimmy.Vetayases@oracle.com lock_clear(&apix_lock); 109112683SJimmy.Vetayases@oracle.com cmn_err(CE_CONT, "Unknown interrupt 0x%x,0x%x " 109212683SJimmy.Vetayases@oracle.com "for %p to remove", APIX_VIRTVEC_CPU(virt_vect), 109312683SJimmy.Vetayases@oracle.com APIX_VIRTVEC_VECTOR(virt_vect), intr_id); 109412683SJimmy.Vetayases@oracle.com return; 109512683SJimmy.Vetayases@oracle.com } 109612683SJimmy.Vetayases@oracle.com virt_vect = APIX_VIRTVECTOR(vecp->v_cpuid, vecp->v_vector); 109712683SJimmy.Vetayases@oracle.com avp = apix_find_av(vecp, intr_id, f); 109812683SJimmy.Vetayases@oracle.com } 109912683SJimmy.Vetayases@oracle.com cpuid = vecp->v_cpuid; 110012683SJimmy.Vetayases@oracle.com 110112683SJimmy.Vetayases@oracle.com /* disable interrupt */ 110212683SJimmy.Vetayases@oracle.com (void) apix_delspl(virt_vect, ipl, 0, 0); 110312683SJimmy.Vetayases@oracle.com 110412683SJimmy.Vetayases@oracle.com /* remove ISR entry */ 110512683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(cpuid); 110612683SJimmy.Vetayases@oracle.com apix_remove_av(vecp, avp); 110712683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(cpuid); 110812683SJimmy.Vetayases@oracle.com 110912683SJimmy.Vetayases@oracle.com lock_clear(&apix_lock); 111012683SJimmy.Vetayases@oracle.com } 111112683SJimmy.Vetayases@oracle.com 111212683SJimmy.Vetayases@oracle.com /* 111312683SJimmy.Vetayases@oracle.com * Device to vector mapping table 111412683SJimmy.Vetayases@oracle.com */ 111512683SJimmy.Vetayases@oracle.com 111612683SJimmy.Vetayases@oracle.com static void 111712683SJimmy.Vetayases@oracle.com apix_clear_dev_map(dev_info_t *dip, int inum, int type) 111812683SJimmy.Vetayases@oracle.com { 111912683SJimmy.Vetayases@oracle.com char *name; 112012683SJimmy.Vetayases@oracle.com major_t major; 112112683SJimmy.Vetayases@oracle.com apix_dev_vector_t *dvp, *prev = NULL; 112212683SJimmy.Vetayases@oracle.com int found = 0; 112312683SJimmy.Vetayases@oracle.com 112412683SJimmy.Vetayases@oracle.com name = ddi_get_name(dip); 112512683SJimmy.Vetayases@oracle.com major = ddi_name_to_major(name); 112612683SJimmy.Vetayases@oracle.com 112712683SJimmy.Vetayases@oracle.com mutex_enter(&apix_mutex); 112812683SJimmy.Vetayases@oracle.com 112912683SJimmy.Vetayases@oracle.com for (dvp = apix_dev_vector[major]; dvp != NULL; 113012683SJimmy.Vetayases@oracle.com prev = dvp, dvp = dvp->dv_next) { 113112683SJimmy.Vetayases@oracle.com if (dvp->dv_dip == dip && dvp->dv_inum == inum && 113212683SJimmy.Vetayases@oracle.com dvp->dv_type == type) { 113312683SJimmy.Vetayases@oracle.com found++; 113412683SJimmy.Vetayases@oracle.com break; 113512683SJimmy.Vetayases@oracle.com } 113612683SJimmy.Vetayases@oracle.com } 113712683SJimmy.Vetayases@oracle.com 113812683SJimmy.Vetayases@oracle.com if (!found) { 113912683SJimmy.Vetayases@oracle.com mutex_exit(&apix_mutex); 114012683SJimmy.Vetayases@oracle.com return; 114112683SJimmy.Vetayases@oracle.com } 114212683SJimmy.Vetayases@oracle.com 114312683SJimmy.Vetayases@oracle.com if (prev != NULL) 114412683SJimmy.Vetayases@oracle.com prev->dv_next = dvp->dv_next; 114512683SJimmy.Vetayases@oracle.com 114612683SJimmy.Vetayases@oracle.com if (apix_dev_vector[major] == dvp) 114712683SJimmy.Vetayases@oracle.com apix_dev_vector[major] = dvp->dv_next; 114812683SJimmy.Vetayases@oracle.com 114912683SJimmy.Vetayases@oracle.com dvp->dv_vector->v_devp = NULL; 115012683SJimmy.Vetayases@oracle.com 115112683SJimmy.Vetayases@oracle.com mutex_exit(&apix_mutex); 115212683SJimmy.Vetayases@oracle.com 115312683SJimmy.Vetayases@oracle.com kmem_free(dvp, sizeof (apix_dev_vector_t)); 115412683SJimmy.Vetayases@oracle.com } 115512683SJimmy.Vetayases@oracle.com 115612683SJimmy.Vetayases@oracle.com void 115712683SJimmy.Vetayases@oracle.com apix_set_dev_map(apix_vector_t *vecp, dev_info_t *dip, int inum) 115812683SJimmy.Vetayases@oracle.com { 115912683SJimmy.Vetayases@oracle.com apix_dev_vector_t *dvp; 116012683SJimmy.Vetayases@oracle.com char *name; 116112683SJimmy.Vetayases@oracle.com major_t major; 116212683SJimmy.Vetayases@oracle.com uint32_t found = 0; 116312683SJimmy.Vetayases@oracle.com 116412683SJimmy.Vetayases@oracle.com ASSERT(dip != NULL); 116512683SJimmy.Vetayases@oracle.com name = ddi_get_name(dip); 116612683SJimmy.Vetayases@oracle.com major = ddi_name_to_major(name); 116712683SJimmy.Vetayases@oracle.com 116812683SJimmy.Vetayases@oracle.com mutex_enter(&apix_mutex); 116912683SJimmy.Vetayases@oracle.com 117012683SJimmy.Vetayases@oracle.com for (dvp = apix_dev_vector[major]; dvp != NULL; 117112683SJimmy.Vetayases@oracle.com dvp = dvp->dv_next) { 117212683SJimmy.Vetayases@oracle.com if (dvp->dv_dip == dip && dvp->dv_inum == inum && 117312683SJimmy.Vetayases@oracle.com dvp->dv_type == vecp->v_type) { 117412683SJimmy.Vetayases@oracle.com found++; 117512683SJimmy.Vetayases@oracle.com break; 117612683SJimmy.Vetayases@oracle.com } 117712683SJimmy.Vetayases@oracle.com } 117812683SJimmy.Vetayases@oracle.com 117912683SJimmy.Vetayases@oracle.com if (found == 0) { /* not found */ 118012683SJimmy.Vetayases@oracle.com dvp = kmem_zalloc(sizeof (apix_dev_vector_t), KM_SLEEP); 118112683SJimmy.Vetayases@oracle.com dvp->dv_dip = dip; 118212683SJimmy.Vetayases@oracle.com dvp->dv_inum = inum; 118312683SJimmy.Vetayases@oracle.com dvp->dv_type = vecp->v_type; 118412683SJimmy.Vetayases@oracle.com 118512683SJimmy.Vetayases@oracle.com dvp->dv_next = apix_dev_vector[major]; 118612683SJimmy.Vetayases@oracle.com apix_dev_vector[major] = dvp; 118712683SJimmy.Vetayases@oracle.com } 118812683SJimmy.Vetayases@oracle.com dvp->dv_vector = vecp; 118912683SJimmy.Vetayases@oracle.com vecp->v_devp = dvp; 119012683SJimmy.Vetayases@oracle.com 119112683SJimmy.Vetayases@oracle.com mutex_exit(&apix_mutex); 119212683SJimmy.Vetayases@oracle.com 119312683SJimmy.Vetayases@oracle.com DDI_INTR_IMPLDBG((CE_CONT, "apix_set_dev_map: dip=0x%p " 119412683SJimmy.Vetayases@oracle.com "inum=0x%x vector=0x%x/0x%x\n", 119512683SJimmy.Vetayases@oracle.com (void *)dip, inum, vecp->v_cpuid, vecp->v_vector)); 119612683SJimmy.Vetayases@oracle.com } 119712683SJimmy.Vetayases@oracle.com 119812683SJimmy.Vetayases@oracle.com apix_vector_t * 119912683SJimmy.Vetayases@oracle.com apix_get_dev_map(dev_info_t *dip, int inum, int type) 120012683SJimmy.Vetayases@oracle.com { 120112683SJimmy.Vetayases@oracle.com char *name; 120212683SJimmy.Vetayases@oracle.com major_t major; 120312683SJimmy.Vetayases@oracle.com apix_dev_vector_t *dvp; 120412683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 120512683SJimmy.Vetayases@oracle.com 120612683SJimmy.Vetayases@oracle.com name = ddi_get_name(dip); 120712683SJimmy.Vetayases@oracle.com if ((major = ddi_name_to_major(name)) == DDI_MAJOR_T_NONE) 120812683SJimmy.Vetayases@oracle.com return (NULL); 120912683SJimmy.Vetayases@oracle.com 121012683SJimmy.Vetayases@oracle.com mutex_enter(&apix_mutex); 121112683SJimmy.Vetayases@oracle.com for (dvp = apix_dev_vector[major]; dvp != NULL; 121212683SJimmy.Vetayases@oracle.com dvp = dvp->dv_next) { 121312683SJimmy.Vetayases@oracle.com if (dvp->dv_dip == dip && dvp->dv_inum == inum && 121412683SJimmy.Vetayases@oracle.com dvp->dv_type == type) { 121512683SJimmy.Vetayases@oracle.com vecp = dvp->dv_vector; 121612683SJimmy.Vetayases@oracle.com mutex_exit(&apix_mutex); 121712683SJimmy.Vetayases@oracle.com return (vecp); 121812683SJimmy.Vetayases@oracle.com } 121912683SJimmy.Vetayases@oracle.com } 122012683SJimmy.Vetayases@oracle.com mutex_exit(&apix_mutex); 122112683SJimmy.Vetayases@oracle.com 122212683SJimmy.Vetayases@oracle.com return (NULL); 122312683SJimmy.Vetayases@oracle.com } 122412683SJimmy.Vetayases@oracle.com 122512683SJimmy.Vetayases@oracle.com /* 122612683SJimmy.Vetayases@oracle.com * Get minimum inum for specified device, used for MSI 122712683SJimmy.Vetayases@oracle.com */ 122812683SJimmy.Vetayases@oracle.com int 122912683SJimmy.Vetayases@oracle.com apix_get_min_dev_inum(dev_info_t *dip, int type) 123012683SJimmy.Vetayases@oracle.com { 123112683SJimmy.Vetayases@oracle.com char *name; 123212683SJimmy.Vetayases@oracle.com major_t major; 123312683SJimmy.Vetayases@oracle.com apix_dev_vector_t *dvp; 123412683SJimmy.Vetayases@oracle.com int inum = -1; 123512683SJimmy.Vetayases@oracle.com 123612683SJimmy.Vetayases@oracle.com name = ddi_get_name(dip); 123712683SJimmy.Vetayases@oracle.com major = ddi_name_to_major(name); 123812683SJimmy.Vetayases@oracle.com 123912683SJimmy.Vetayases@oracle.com mutex_enter(&apix_mutex); 124012683SJimmy.Vetayases@oracle.com for (dvp = apix_dev_vector[major]; dvp != NULL; 124112683SJimmy.Vetayases@oracle.com dvp = dvp->dv_next) { 124212683SJimmy.Vetayases@oracle.com if (dvp->dv_dip == dip && dvp->dv_type == type) { 124312683SJimmy.Vetayases@oracle.com if (inum == -1) 124412683SJimmy.Vetayases@oracle.com inum = dvp->dv_inum; 124512683SJimmy.Vetayases@oracle.com else 124612683SJimmy.Vetayases@oracle.com inum = (dvp->dv_inum < inum) ? 124712683SJimmy.Vetayases@oracle.com dvp->dv_inum : inum; 124812683SJimmy.Vetayases@oracle.com } 124912683SJimmy.Vetayases@oracle.com } 125012683SJimmy.Vetayases@oracle.com mutex_exit(&apix_mutex); 125112683SJimmy.Vetayases@oracle.com 125212683SJimmy.Vetayases@oracle.com return (inum); 125312683SJimmy.Vetayases@oracle.com } 125412683SJimmy.Vetayases@oracle.com 125512683SJimmy.Vetayases@oracle.com int 125612683SJimmy.Vetayases@oracle.com apix_get_max_dev_inum(dev_info_t *dip, int type) 125712683SJimmy.Vetayases@oracle.com { 125812683SJimmy.Vetayases@oracle.com char *name; 125912683SJimmy.Vetayases@oracle.com major_t major; 126012683SJimmy.Vetayases@oracle.com apix_dev_vector_t *dvp; 126112683SJimmy.Vetayases@oracle.com int inum = -1; 126212683SJimmy.Vetayases@oracle.com 126312683SJimmy.Vetayases@oracle.com name = ddi_get_name(dip); 126412683SJimmy.Vetayases@oracle.com major = ddi_name_to_major(name); 126512683SJimmy.Vetayases@oracle.com 126612683SJimmy.Vetayases@oracle.com mutex_enter(&apix_mutex); 126712683SJimmy.Vetayases@oracle.com for (dvp = apix_dev_vector[major]; dvp != NULL; 126812683SJimmy.Vetayases@oracle.com dvp = dvp->dv_next) { 126912683SJimmy.Vetayases@oracle.com if (dvp->dv_dip == dip && dvp->dv_type == type) { 127012683SJimmy.Vetayases@oracle.com if (inum == -1) 127112683SJimmy.Vetayases@oracle.com inum = dvp->dv_inum; 127212683SJimmy.Vetayases@oracle.com else 127312683SJimmy.Vetayases@oracle.com inum = (dvp->dv_inum > inum) ? 127412683SJimmy.Vetayases@oracle.com dvp->dv_inum : inum; 127512683SJimmy.Vetayases@oracle.com } 127612683SJimmy.Vetayases@oracle.com } 127712683SJimmy.Vetayases@oracle.com mutex_exit(&apix_mutex); 127812683SJimmy.Vetayases@oracle.com 127912683SJimmy.Vetayases@oracle.com return (inum); 128012683SJimmy.Vetayases@oracle.com } 128112683SJimmy.Vetayases@oracle.com 128212683SJimmy.Vetayases@oracle.com /* 128312683SJimmy.Vetayases@oracle.com * Major to cpu binding, for INTR_ROUND_ROBIN_WITH_AFFINITY cpu 128412683SJimmy.Vetayases@oracle.com * binding policy 128512683SJimmy.Vetayases@oracle.com */ 128612683SJimmy.Vetayases@oracle.com 128712683SJimmy.Vetayases@oracle.com static uint32_t 128812683SJimmy.Vetayases@oracle.com apix_get_dev_binding(dev_info_t *dip) 128912683SJimmy.Vetayases@oracle.com { 129012683SJimmy.Vetayases@oracle.com major_t major; 129112683SJimmy.Vetayases@oracle.com char *name; 129212683SJimmy.Vetayases@oracle.com uint32_t cpu = IRQ_UNINIT; 129312683SJimmy.Vetayases@oracle.com 129412683SJimmy.Vetayases@oracle.com name = ddi_get_name(dip); 129512683SJimmy.Vetayases@oracle.com major = ddi_name_to_major(name); 129612683SJimmy.Vetayases@oracle.com if (major < devcnt) { 129712683SJimmy.Vetayases@oracle.com mutex_enter(&apix_mutex); 129812683SJimmy.Vetayases@oracle.com cpu = apix_major_to_cpu[major]; 129912683SJimmy.Vetayases@oracle.com mutex_exit(&apix_mutex); 130012683SJimmy.Vetayases@oracle.com } 130112683SJimmy.Vetayases@oracle.com 130212683SJimmy.Vetayases@oracle.com return (cpu); 130312683SJimmy.Vetayases@oracle.com } 130412683SJimmy.Vetayases@oracle.com 130512683SJimmy.Vetayases@oracle.com static void 130612683SJimmy.Vetayases@oracle.com apix_set_dev_binding(dev_info_t *dip, uint32_t cpu) 130712683SJimmy.Vetayases@oracle.com { 130812683SJimmy.Vetayases@oracle.com major_t major; 130912683SJimmy.Vetayases@oracle.com char *name; 131012683SJimmy.Vetayases@oracle.com 131112683SJimmy.Vetayases@oracle.com /* setup major to cpu mapping */ 131212683SJimmy.Vetayases@oracle.com name = ddi_get_name(dip); 131312683SJimmy.Vetayases@oracle.com major = ddi_name_to_major(name); 131412683SJimmy.Vetayases@oracle.com if (apix_major_to_cpu[major] == IRQ_UNINIT) { 131512683SJimmy.Vetayases@oracle.com mutex_enter(&apix_mutex); 131612683SJimmy.Vetayases@oracle.com apix_major_to_cpu[major] = cpu; 131712683SJimmy.Vetayases@oracle.com mutex_exit(&apix_mutex); 131812683SJimmy.Vetayases@oracle.com } 131912683SJimmy.Vetayases@oracle.com } 132012683SJimmy.Vetayases@oracle.com 132112683SJimmy.Vetayases@oracle.com /* 132212683SJimmy.Vetayases@oracle.com * return the cpu to which this intr should be bound. 132312683SJimmy.Vetayases@oracle.com * Check properties or any other mechanism to see if user wants it 132412683SJimmy.Vetayases@oracle.com * bound to a specific CPU. If so, return the cpu id with high bit set. 132512683SJimmy.Vetayases@oracle.com * If not, use the policy to choose a cpu and return the id. 132612683SJimmy.Vetayases@oracle.com */ 132712683SJimmy.Vetayases@oracle.com uint32_t 132812683SJimmy.Vetayases@oracle.com apix_bind_cpu(dev_info_t *dip) 132912683SJimmy.Vetayases@oracle.com { 133012683SJimmy.Vetayases@oracle.com int instance, instno, prop_len, bind_cpu, count; 133112683SJimmy.Vetayases@oracle.com uint_t i, rc; 133212683SJimmy.Vetayases@oracle.com major_t major; 133312683SJimmy.Vetayases@oracle.com char *name, *drv_name, *prop_val, *cptr; 133412683SJimmy.Vetayases@oracle.com char prop_name[32]; 133512683SJimmy.Vetayases@oracle.com 133612683SJimmy.Vetayases@oracle.com lock_set(&apix_lock); 133712683SJimmy.Vetayases@oracle.com 133812683SJimmy.Vetayases@oracle.com if (apic_intr_policy == INTR_LOWEST_PRIORITY) { 133912683SJimmy.Vetayases@oracle.com cmn_err(CE_WARN, "apix: unsupported interrupt binding policy " 134012683SJimmy.Vetayases@oracle.com "LOWEST PRIORITY, use ROUND ROBIN instead"); 134112683SJimmy.Vetayases@oracle.com apic_intr_policy = INTR_ROUND_ROBIN; 134212683SJimmy.Vetayases@oracle.com } 134312683SJimmy.Vetayases@oracle.com 134412683SJimmy.Vetayases@oracle.com if (apic_nproc == 1) { 134512683SJimmy.Vetayases@oracle.com lock_clear(&apix_lock); 134612683SJimmy.Vetayases@oracle.com return (0); 134712683SJimmy.Vetayases@oracle.com } 134812683SJimmy.Vetayases@oracle.com 134912683SJimmy.Vetayases@oracle.com drv_name = NULL; 135012683SJimmy.Vetayases@oracle.com rc = DDI_PROP_NOT_FOUND; 135112683SJimmy.Vetayases@oracle.com major = (major_t)-1; 135212683SJimmy.Vetayases@oracle.com if (dip != NULL) { 135312683SJimmy.Vetayases@oracle.com name = ddi_get_name(dip); 135412683SJimmy.Vetayases@oracle.com major = ddi_name_to_major(name); 135512683SJimmy.Vetayases@oracle.com drv_name = ddi_major_to_name(major); 135612683SJimmy.Vetayases@oracle.com instance = ddi_get_instance(dip); 135712683SJimmy.Vetayases@oracle.com if (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) { 135812683SJimmy.Vetayases@oracle.com bind_cpu = apix_get_dev_binding(dip); 135912683SJimmy.Vetayases@oracle.com if (bind_cpu != IRQ_UNINIT) { 136012683SJimmy.Vetayases@oracle.com lock_clear(&apix_lock); 136112683SJimmy.Vetayases@oracle.com return (bind_cpu); 136212683SJimmy.Vetayases@oracle.com } 136312683SJimmy.Vetayases@oracle.com } 136412683SJimmy.Vetayases@oracle.com /* 136512683SJimmy.Vetayases@oracle.com * search for "drvname"_intpt_bind_cpus property first, the 136612683SJimmy.Vetayases@oracle.com * syntax of the property should be "a[,b,c,...]" where 136712683SJimmy.Vetayases@oracle.com * instance 0 binds to cpu a, instance 1 binds to cpu b, 136812683SJimmy.Vetayases@oracle.com * instance 3 binds to cpu c... 136912683SJimmy.Vetayases@oracle.com * ddi_getlongprop() will search /option first, then / 137012683SJimmy.Vetayases@oracle.com * if "drvname"_intpt_bind_cpus doesn't exist, then find 137112683SJimmy.Vetayases@oracle.com * intpt_bind_cpus property. The syntax is the same, and 137212683SJimmy.Vetayases@oracle.com * it applies to all the devices if its "drvname" specific 137312683SJimmy.Vetayases@oracle.com * property doesn't exist 137412683SJimmy.Vetayases@oracle.com */ 137512683SJimmy.Vetayases@oracle.com (void) strcpy(prop_name, drv_name); 137612683SJimmy.Vetayases@oracle.com (void) strcat(prop_name, "_intpt_bind_cpus"); 137712683SJimmy.Vetayases@oracle.com rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, 0, prop_name, 137812683SJimmy.Vetayases@oracle.com (caddr_t)&prop_val, &prop_len); 137912683SJimmy.Vetayases@oracle.com if (rc != DDI_PROP_SUCCESS) { 138012683SJimmy.Vetayases@oracle.com rc = ddi_getlongprop(DDI_DEV_T_ANY, dip, 0, 138112683SJimmy.Vetayases@oracle.com "intpt_bind_cpus", (caddr_t)&prop_val, &prop_len); 138212683SJimmy.Vetayases@oracle.com } 138312683SJimmy.Vetayases@oracle.com } 138412683SJimmy.Vetayases@oracle.com if (rc == DDI_PROP_SUCCESS) { 138512683SJimmy.Vetayases@oracle.com for (i = count = 0; i < (prop_len - 1); i++) 138612683SJimmy.Vetayases@oracle.com if (prop_val[i] == ',') 138712683SJimmy.Vetayases@oracle.com count++; 138812683SJimmy.Vetayases@oracle.com if (prop_val[i-1] != ',') 138912683SJimmy.Vetayases@oracle.com count++; 139012683SJimmy.Vetayases@oracle.com /* 139112683SJimmy.Vetayases@oracle.com * if somehow the binding instances defined in the 139212683SJimmy.Vetayases@oracle.com * property are not enough for this instno., then 139312683SJimmy.Vetayases@oracle.com * reuse the pattern for the next instance until 139412683SJimmy.Vetayases@oracle.com * it reaches the requested instno 139512683SJimmy.Vetayases@oracle.com */ 139612683SJimmy.Vetayases@oracle.com instno = instance % count; 139712683SJimmy.Vetayases@oracle.com i = 0; 139812683SJimmy.Vetayases@oracle.com cptr = prop_val; 139912683SJimmy.Vetayases@oracle.com while (i < instno) 140012683SJimmy.Vetayases@oracle.com if (*cptr++ == ',') 140112683SJimmy.Vetayases@oracle.com i++; 140212683SJimmy.Vetayases@oracle.com bind_cpu = stoi(&cptr); 140312683SJimmy.Vetayases@oracle.com kmem_free(prop_val, prop_len); 140412683SJimmy.Vetayases@oracle.com /* if specific cpu is bogus, then default to cpu 0 */ 140512683SJimmy.Vetayases@oracle.com if (bind_cpu >= apic_nproc) { 140612683SJimmy.Vetayases@oracle.com cmn_err(CE_WARN, "apix: %s=%s: CPU %d not present", 140712683SJimmy.Vetayases@oracle.com prop_name, prop_val, bind_cpu); 140812683SJimmy.Vetayases@oracle.com bind_cpu = 0; 140912683SJimmy.Vetayases@oracle.com } else { 141012683SJimmy.Vetayases@oracle.com /* indicate that we are bound at user request */ 141112683SJimmy.Vetayases@oracle.com bind_cpu |= IRQ_USER_BOUND; 141212683SJimmy.Vetayases@oracle.com } 141312683SJimmy.Vetayases@oracle.com /* 141412683SJimmy.Vetayases@oracle.com * no need to check apic_cpus[].aci_status, if specific cpu is 141512683SJimmy.Vetayases@oracle.com * not up, then post_cpu_start will handle it. 141612683SJimmy.Vetayases@oracle.com */ 141712683SJimmy.Vetayases@oracle.com } else { 141812683SJimmy.Vetayases@oracle.com bind_cpu = apic_get_next_bind_cpu(); 141912683SJimmy.Vetayases@oracle.com } 142012683SJimmy.Vetayases@oracle.com 142112683SJimmy.Vetayases@oracle.com lock_clear(&apix_lock); 142212683SJimmy.Vetayases@oracle.com 142312683SJimmy.Vetayases@oracle.com return ((uint32_t)bind_cpu); 142412683SJimmy.Vetayases@oracle.com } 142512683SJimmy.Vetayases@oracle.com 142612683SJimmy.Vetayases@oracle.com static boolean_t 142712683SJimmy.Vetayases@oracle.com apix_is_cpu_enabled(processorid_t cpuid) 142812683SJimmy.Vetayases@oracle.com { 142912683SJimmy.Vetayases@oracle.com apic_cpus_info_t *cpu_infop; 143012683SJimmy.Vetayases@oracle.com 143112683SJimmy.Vetayases@oracle.com cpu_infop = &apic_cpus[cpuid]; 143212683SJimmy.Vetayases@oracle.com 143312683SJimmy.Vetayases@oracle.com if ((cpu_infop->aci_status & APIC_CPU_INTR_ENABLE) == 0) 143412683SJimmy.Vetayases@oracle.com return (B_FALSE); 143512683SJimmy.Vetayases@oracle.com 143612683SJimmy.Vetayases@oracle.com return (B_TRUE); 143712683SJimmy.Vetayases@oracle.com } 143812683SJimmy.Vetayases@oracle.com 143912683SJimmy.Vetayases@oracle.com /* 144012683SJimmy.Vetayases@oracle.com * Must be called with apix_lock held. This function can be 144112683SJimmy.Vetayases@oracle.com * called from above lock level by apix_intr_redistribute(). 144212683SJimmy.Vetayases@oracle.com * 144312683SJimmy.Vetayases@oracle.com * Arguments: 144412683SJimmy.Vetayases@oracle.com * vecp : Vector to be rebound 144512683SJimmy.Vetayases@oracle.com * tocpu : Target cpu. IRQ_UNINIT means target is vecp->v_cpuid. 144612683SJimmy.Vetayases@oracle.com * count : Number of continuous vectors 144712683SJimmy.Vetayases@oracle.com * 144812683SJimmy.Vetayases@oracle.com * Return new vector being bound to 144912683SJimmy.Vetayases@oracle.com */ 145012683SJimmy.Vetayases@oracle.com apix_vector_t * 145112683SJimmy.Vetayases@oracle.com apix_rebind(apix_vector_t *vecp, processorid_t newcpu, int count) 145212683SJimmy.Vetayases@oracle.com { 145312683SJimmy.Vetayases@oracle.com apix_vector_t *newp, *oldp; 145412683SJimmy.Vetayases@oracle.com processorid_t oldcpu = vecp->v_cpuid; 145512683SJimmy.Vetayases@oracle.com uchar_t newvec, oldvec = vecp->v_vector; 145612683SJimmy.Vetayases@oracle.com int i; 145712683SJimmy.Vetayases@oracle.com 145812683SJimmy.Vetayases@oracle.com ASSERT(LOCK_HELD(&apix_lock) && count > 0); 145912683SJimmy.Vetayases@oracle.com 146012683SJimmy.Vetayases@oracle.com if (!apix_is_cpu_enabled(newcpu)) 146112683SJimmy.Vetayases@oracle.com return (NULL); 146212683SJimmy.Vetayases@oracle.com 146312683SJimmy.Vetayases@oracle.com if (vecp->v_cpuid == newcpu) /* rebind to the same cpu */ 146412683SJimmy.Vetayases@oracle.com return (vecp); 146512683SJimmy.Vetayases@oracle.com 146612683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(oldcpu); 146712683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(newcpu); 146812683SJimmy.Vetayases@oracle.com 146912683SJimmy.Vetayases@oracle.com /* allocate vector */ 147012683SJimmy.Vetayases@oracle.com if (count == 1) 147112683SJimmy.Vetayases@oracle.com newp = apix_alloc_vector_oncpu(newcpu, NULL, 0, vecp->v_type); 147212683SJimmy.Vetayases@oracle.com else { 147312683SJimmy.Vetayases@oracle.com ASSERT(vecp->v_type == APIX_TYPE_MSI); 147412683SJimmy.Vetayases@oracle.com newp = apix_alloc_nvectors_oncpu(newcpu, NULL, 0, count, 147512683SJimmy.Vetayases@oracle.com vecp->v_type); 147612683SJimmy.Vetayases@oracle.com } 147712683SJimmy.Vetayases@oracle.com if (newp == NULL) { 147812683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(newcpu); 147912683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(oldcpu); 148012683SJimmy.Vetayases@oracle.com return (NULL); 148112683SJimmy.Vetayases@oracle.com } 148212683SJimmy.Vetayases@oracle.com 148312683SJimmy.Vetayases@oracle.com newvec = newp->v_vector; 148412683SJimmy.Vetayases@oracle.com apix_dup_vectors(vecp, newp, count); 148512683SJimmy.Vetayases@oracle.com 148612683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(newcpu); 148712683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(oldcpu); 148812683SJimmy.Vetayases@oracle.com 148912683SJimmy.Vetayases@oracle.com if (!DDI_INTR_IS_MSI_OR_MSIX(vecp->v_type)) { 149012683SJimmy.Vetayases@oracle.com ASSERT(count == 1); 149112683SJimmy.Vetayases@oracle.com if (apix_intx_rebind(vecp->v_inum, newcpu, newvec) != 0) { 149212683SJimmy.Vetayases@oracle.com struct autovec *avp; 149312683SJimmy.Vetayases@oracle.com int inum; 149412683SJimmy.Vetayases@oracle.com 149512683SJimmy.Vetayases@oracle.com /* undo duplication */ 149612683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(oldcpu); 149712683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(newcpu); 149812683SJimmy.Vetayases@oracle.com for (avp = newp->v_autovect; avp != NULL; 149912683SJimmy.Vetayases@oracle.com avp = avp->av_link) { 150012683SJimmy.Vetayases@oracle.com if (avp->av_dip != NULL) { 150112683SJimmy.Vetayases@oracle.com inum = GET_INTR_INUM(avp->av_intr_id); 150212683SJimmy.Vetayases@oracle.com apix_set_dev_map(vecp, avp->av_dip, 150312683SJimmy.Vetayases@oracle.com inum); 150412683SJimmy.Vetayases@oracle.com } 150512683SJimmy.Vetayases@oracle.com apix_remove_av(newp, avp); 150612683SJimmy.Vetayases@oracle.com } 150712683SJimmy.Vetayases@oracle.com apix_cleanup_vector(newp); 150812683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(newcpu); 150912683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(oldcpu); 151012683SJimmy.Vetayases@oracle.com APIC_VERBOSE(REBIND, (CE_CONT, "apix: rebind fixed " 151112683SJimmy.Vetayases@oracle.com "interrupt 0x%x to cpu %d failed\n", 151212683SJimmy.Vetayases@oracle.com vecp->v_inum, newcpu)); 151312683SJimmy.Vetayases@oracle.com return (NULL); 151412683SJimmy.Vetayases@oracle.com } 151512683SJimmy.Vetayases@oracle.com 151612683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(oldcpu); 151712683SJimmy.Vetayases@oracle.com (void) apix_obsolete_vector(vecp); 151812683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(oldcpu); 151912683SJimmy.Vetayases@oracle.com APIC_VERBOSE(REBIND, (CE_CONT, "apix: rebind fixed interrupt" 152012683SJimmy.Vetayases@oracle.com " 0x%x/0x%x to 0x%x/0x%x\n", 152112683SJimmy.Vetayases@oracle.com oldcpu, oldvec, newcpu, newvec)); 152212683SJimmy.Vetayases@oracle.com return (newp); 152312683SJimmy.Vetayases@oracle.com } 152412683SJimmy.Vetayases@oracle.com 152512683SJimmy.Vetayases@oracle.com for (i = 0; i < count; i++) { 152612683SJimmy.Vetayases@oracle.com oldp = xv_vector(oldcpu, oldvec + i); 152712683SJimmy.Vetayases@oracle.com newp = xv_vector(newcpu, newvec + i); 152812683SJimmy.Vetayases@oracle.com 152912683SJimmy.Vetayases@oracle.com if (newp->v_share > 0) { 153012683SJimmy.Vetayases@oracle.com APIX_SET_REBIND_INFO(oldp, newp); 153112683SJimmy.Vetayases@oracle.com 153212683SJimmy.Vetayases@oracle.com apix_enable_vector(newp); 153312683SJimmy.Vetayases@oracle.com 153412683SJimmy.Vetayases@oracle.com APIX_CLR_REBIND_INFO(); 153512683SJimmy.Vetayases@oracle.com } 153612683SJimmy.Vetayases@oracle.com 153712683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(oldcpu); 153812683SJimmy.Vetayases@oracle.com (void) apix_obsolete_vector(oldp); 153912683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(oldcpu); 154012683SJimmy.Vetayases@oracle.com } 154112683SJimmy.Vetayases@oracle.com APIC_VERBOSE(REBIND, (CE_CONT, "apix: rebind vector 0x%x/0x%x " 154212683SJimmy.Vetayases@oracle.com "to 0x%x/0x%x, count=%d\n", 154312683SJimmy.Vetayases@oracle.com oldcpu, oldvec, newcpu, newvec, count)); 154412683SJimmy.Vetayases@oracle.com 154512683SJimmy.Vetayases@oracle.com return (xv_vector(newcpu, newvec)); 154612683SJimmy.Vetayases@oracle.com } 154712683SJimmy.Vetayases@oracle.com 154812683SJimmy.Vetayases@oracle.com /* 154912683SJimmy.Vetayases@oracle.com * Senarios include: 155012683SJimmy.Vetayases@oracle.com * a. add_avintr() is called before irqp initialized (legacy) 155112683SJimmy.Vetayases@oracle.com * b. irqp is initialized, vector is not allocated (fixed interrupts) 155212683SJimmy.Vetayases@oracle.com * c. irqp is initialized, vector is allocated (shared interrupts) 155312683SJimmy.Vetayases@oracle.com */ 155412683SJimmy.Vetayases@oracle.com apix_vector_t * 155512683SJimmy.Vetayases@oracle.com apix_alloc_intx(dev_info_t *dip, int inum, int irqno) 155612683SJimmy.Vetayases@oracle.com { 155712683SJimmy.Vetayases@oracle.com apic_irq_t *irqp; 155812683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 155912683SJimmy.Vetayases@oracle.com 156012683SJimmy.Vetayases@oracle.com /* 156112683SJimmy.Vetayases@oracle.com * Allocate IRQ. Caller is later responsible for the 156212683SJimmy.Vetayases@oracle.com * initialization 156312683SJimmy.Vetayases@oracle.com */ 156412683SJimmy.Vetayases@oracle.com mutex_enter(&airq_mutex); 156512683SJimmy.Vetayases@oracle.com if ((irqp = apic_irq_table[irqno]) == NULL) { 156612683SJimmy.Vetayases@oracle.com /* allocate irq */ 156712683SJimmy.Vetayases@oracle.com irqp = kmem_zalloc(sizeof (apic_irq_t), KM_SLEEP); 156812683SJimmy.Vetayases@oracle.com irqp->airq_mps_intr_index = FREE_INDEX; 156912683SJimmy.Vetayases@oracle.com apic_irq_table[irqno] = irqp; 157012683SJimmy.Vetayases@oracle.com } 157112683SJimmy.Vetayases@oracle.com if (irqp->airq_mps_intr_index == FREE_INDEX) { 157212683SJimmy.Vetayases@oracle.com irqp->airq_mps_intr_index = DEFAULT_INDEX; 157312683SJimmy.Vetayases@oracle.com irqp->airq_cpu = IRQ_UNINIT; 157412683SJimmy.Vetayases@oracle.com irqp->airq_origirq = (uchar_t)irqno; 157512683SJimmy.Vetayases@oracle.com } 157612683SJimmy.Vetayases@oracle.com 157712683SJimmy.Vetayases@oracle.com mutex_exit(&airq_mutex); 157812683SJimmy.Vetayases@oracle.com 157912683SJimmy.Vetayases@oracle.com /* 158012683SJimmy.Vetayases@oracle.com * allocate vector 158112683SJimmy.Vetayases@oracle.com */ 158212683SJimmy.Vetayases@oracle.com if (irqp->airq_cpu == IRQ_UNINIT) { 158312683SJimmy.Vetayases@oracle.com uint32_t bindcpu, cpuid; 158412683SJimmy.Vetayases@oracle.com 158512683SJimmy.Vetayases@oracle.com /* select cpu by system policy */ 158612683SJimmy.Vetayases@oracle.com bindcpu = apix_bind_cpu(dip); 158712683SJimmy.Vetayases@oracle.com cpuid = bindcpu & ~IRQ_USER_BOUND; 158812683SJimmy.Vetayases@oracle.com 158912683SJimmy.Vetayases@oracle.com /* allocate vector */ 159012683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(cpuid); 159112683SJimmy.Vetayases@oracle.com 159212683SJimmy.Vetayases@oracle.com if ((vecp = apix_alloc_vector_oncpu(bindcpu, dip, inum, 159312683SJimmy.Vetayases@oracle.com APIX_TYPE_FIXED)) == NULL) { 159412683SJimmy.Vetayases@oracle.com cmn_err(CE_WARN, "No interrupt vector for irq %x", 159512683SJimmy.Vetayases@oracle.com irqno); 159612683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(cpuid); 159712683SJimmy.Vetayases@oracle.com return (NULL); 159812683SJimmy.Vetayases@oracle.com } 159912683SJimmy.Vetayases@oracle.com vecp->v_inum = irqno; 160012683SJimmy.Vetayases@oracle.com vecp->v_flags |= APIX_VECT_MASKABLE; 160112683SJimmy.Vetayases@oracle.com 160212683SJimmy.Vetayases@oracle.com apix_intx_set_vector(irqno, vecp->v_cpuid, vecp->v_vector); 160312683SJimmy.Vetayases@oracle.com 160412683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(cpuid); 160512683SJimmy.Vetayases@oracle.com } else { 160612683SJimmy.Vetayases@oracle.com vecp = xv_vector(irqp->airq_cpu, irqp->airq_vector); 160712683SJimmy.Vetayases@oracle.com ASSERT(!IS_VECT_FREE(vecp)); 160812683SJimmy.Vetayases@oracle.com 160912683SJimmy.Vetayases@oracle.com if (dip != NULL) 161012683SJimmy.Vetayases@oracle.com apix_set_dev_map(vecp, dip, inum); 161112683SJimmy.Vetayases@oracle.com } 161212683SJimmy.Vetayases@oracle.com 161312683SJimmy.Vetayases@oracle.com if ((dip != NULL) && 161412683SJimmy.Vetayases@oracle.com (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) && 161512683SJimmy.Vetayases@oracle.com ((vecp->v_flags & APIX_VECT_USER_BOUND) == 0)) 161612683SJimmy.Vetayases@oracle.com apix_set_dev_binding(dip, vecp->v_cpuid); 161712683SJimmy.Vetayases@oracle.com 161812683SJimmy.Vetayases@oracle.com apix_dprint_vector(vecp, dip, 1); 161912683SJimmy.Vetayases@oracle.com 162012683SJimmy.Vetayases@oracle.com return (vecp); 162112683SJimmy.Vetayases@oracle.com } 162212683SJimmy.Vetayases@oracle.com 162312683SJimmy.Vetayases@oracle.com int 162412683SJimmy.Vetayases@oracle.com apix_alloc_msi(dev_info_t *dip, int inum, int count, int behavior) 162512683SJimmy.Vetayases@oracle.com { 162612683SJimmy.Vetayases@oracle.com int i, cap_ptr, rcount = count; 162712683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 162812683SJimmy.Vetayases@oracle.com processorid_t bindcpu, cpuid; 162912683SJimmy.Vetayases@oracle.com ushort_t msi_ctrl; 163012683SJimmy.Vetayases@oracle.com ddi_acc_handle_t handle; 163112683SJimmy.Vetayases@oracle.com 163212683SJimmy.Vetayases@oracle.com DDI_INTR_IMPLDBG((CE_CONT, "apix_alloc_msi_vectors: dip=0x%p " 163312683SJimmy.Vetayases@oracle.com "inum=0x%x count=0x%x behavior=%d\n", 163412683SJimmy.Vetayases@oracle.com (void *)dip, inum, count, behavior)); 163512683SJimmy.Vetayases@oracle.com 163612683SJimmy.Vetayases@oracle.com if (count > 1) { 163712683SJimmy.Vetayases@oracle.com if (behavior == DDI_INTR_ALLOC_STRICT && 163812683SJimmy.Vetayases@oracle.com apic_multi_msi_enable == 0) 163912683SJimmy.Vetayases@oracle.com return (0); 164012683SJimmy.Vetayases@oracle.com if (apic_multi_msi_enable == 0) 164112683SJimmy.Vetayases@oracle.com count = 1; 164212683SJimmy.Vetayases@oracle.com } 164312683SJimmy.Vetayases@oracle.com 164412683SJimmy.Vetayases@oracle.com /* Check whether it supports per-vector masking */ 164512683SJimmy.Vetayases@oracle.com cap_ptr = i_ddi_get_msi_msix_cap_ptr(dip); 164612683SJimmy.Vetayases@oracle.com handle = i_ddi_get_pci_config_handle(dip); 164712683SJimmy.Vetayases@oracle.com msi_ctrl = pci_config_get16(handle, cap_ptr + PCI_MSI_CTRL); 164812683SJimmy.Vetayases@oracle.com 164912683SJimmy.Vetayases@oracle.com /* bind to cpu */ 165012683SJimmy.Vetayases@oracle.com bindcpu = apix_bind_cpu(dip); 165112683SJimmy.Vetayases@oracle.com cpuid = bindcpu & ~IRQ_USER_BOUND; 165212683SJimmy.Vetayases@oracle.com 165312683SJimmy.Vetayases@oracle.com /* if not ISP2, then round it down */ 165412683SJimmy.Vetayases@oracle.com if (!ISP2(rcount)) 165512683SJimmy.Vetayases@oracle.com rcount = 1 << (highbit(rcount) - 1); 165612683SJimmy.Vetayases@oracle.com 165712683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(cpuid); 165812683SJimmy.Vetayases@oracle.com for (vecp = NULL; rcount > 0; rcount >>= 1) { 165912683SJimmy.Vetayases@oracle.com vecp = apix_alloc_nvectors_oncpu(bindcpu, dip, inum, rcount, 166012683SJimmy.Vetayases@oracle.com APIX_TYPE_MSI); 166112683SJimmy.Vetayases@oracle.com if (vecp != NULL || behavior == DDI_INTR_ALLOC_STRICT) 166212683SJimmy.Vetayases@oracle.com break; 166312683SJimmy.Vetayases@oracle.com } 166412683SJimmy.Vetayases@oracle.com for (i = 0; vecp && i < rcount; i++) 166512683SJimmy.Vetayases@oracle.com xv_vector(vecp->v_cpuid, vecp->v_vector + i)->v_flags |= 166612683SJimmy.Vetayases@oracle.com (msi_ctrl & PCI_MSI_PVM_MASK) ? APIX_VECT_MASKABLE : 0; 166712683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(cpuid); 166812683SJimmy.Vetayases@oracle.com if (vecp == NULL) { 166912683SJimmy.Vetayases@oracle.com APIC_VERBOSE(INTR, (CE_CONT, 167012683SJimmy.Vetayases@oracle.com "apix_alloc_msi: no %d cont vectors found on cpu 0x%x\n", 167112683SJimmy.Vetayases@oracle.com count, bindcpu)); 167212683SJimmy.Vetayases@oracle.com return (0); 167312683SJimmy.Vetayases@oracle.com } 167412683SJimmy.Vetayases@oracle.com 167512683SJimmy.Vetayases@oracle.com /* major to cpu binding */ 167612683SJimmy.Vetayases@oracle.com if ((apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) && 167712683SJimmy.Vetayases@oracle.com ((vecp->v_flags & APIX_VECT_USER_BOUND) == 0)) 167812683SJimmy.Vetayases@oracle.com apix_set_dev_binding(dip, vecp->v_cpuid); 167912683SJimmy.Vetayases@oracle.com 168012683SJimmy.Vetayases@oracle.com apix_dprint_vector(vecp, dip, rcount); 168112683SJimmy.Vetayases@oracle.com 168212683SJimmy.Vetayases@oracle.com return (rcount); 168312683SJimmy.Vetayases@oracle.com } 168412683SJimmy.Vetayases@oracle.com 168512683SJimmy.Vetayases@oracle.com int 168612683SJimmy.Vetayases@oracle.com apix_alloc_msix(dev_info_t *dip, int inum, int count, int behavior) 168712683SJimmy.Vetayases@oracle.com { 168812683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 168912683SJimmy.Vetayases@oracle.com processorid_t bindcpu, cpuid; 169012683SJimmy.Vetayases@oracle.com int i; 169112683SJimmy.Vetayases@oracle.com 169212683SJimmy.Vetayases@oracle.com for (i = 0; i < count; i++) { 169312683SJimmy.Vetayases@oracle.com /* select cpu by system policy */ 169412683SJimmy.Vetayases@oracle.com bindcpu = apix_bind_cpu(dip); 169512683SJimmy.Vetayases@oracle.com cpuid = bindcpu & ~IRQ_USER_BOUND; 169612683SJimmy.Vetayases@oracle.com 169712683SJimmy.Vetayases@oracle.com /* allocate vector */ 169812683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(cpuid); 169912683SJimmy.Vetayases@oracle.com if ((vecp = apix_alloc_vector_oncpu(bindcpu, dip, inum + i, 170012683SJimmy.Vetayases@oracle.com APIX_TYPE_MSIX)) == NULL) { 170112683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(cpuid); 170212683SJimmy.Vetayases@oracle.com APIC_VERBOSE(INTR, (CE_CONT, "apix_alloc_msix: " 170312683SJimmy.Vetayases@oracle.com "allocate msix for device dip=%p, inum=%d on" 170412683SJimmy.Vetayases@oracle.com " cpu %d failed", (void *)dip, inum + i, bindcpu)); 170512683SJimmy.Vetayases@oracle.com break; 170612683SJimmy.Vetayases@oracle.com } 170712683SJimmy.Vetayases@oracle.com vecp->v_flags |= APIX_VECT_MASKABLE; 170812683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(cpuid); 170912683SJimmy.Vetayases@oracle.com 171012683SJimmy.Vetayases@oracle.com /* major to cpu mapping */ 171112683SJimmy.Vetayases@oracle.com if ((i == 0) && 171212683SJimmy.Vetayases@oracle.com (apic_intr_policy == INTR_ROUND_ROBIN_WITH_AFFINITY) && 171312683SJimmy.Vetayases@oracle.com ((vecp->v_flags & APIX_VECT_USER_BOUND) == 0)) 171412683SJimmy.Vetayases@oracle.com apix_set_dev_binding(dip, vecp->v_cpuid); 171512683SJimmy.Vetayases@oracle.com 171612683SJimmy.Vetayases@oracle.com apix_dprint_vector(vecp, dip, 1); 171712683SJimmy.Vetayases@oracle.com } 171812683SJimmy.Vetayases@oracle.com 171912683SJimmy.Vetayases@oracle.com if (i < count && behavior == DDI_INTR_ALLOC_STRICT) { 172012683SJimmy.Vetayases@oracle.com APIC_VERBOSE(INTR, (CE_WARN, "apix_alloc_msix: " 172112683SJimmy.Vetayases@oracle.com "strictly allocate %d vectors failed, got %d\n", 172212683SJimmy.Vetayases@oracle.com count, i)); 172312683SJimmy.Vetayases@oracle.com apix_free_vectors(dip, inum, i, APIX_TYPE_MSIX); 172412683SJimmy.Vetayases@oracle.com i = 0; 172512683SJimmy.Vetayases@oracle.com } 172612683SJimmy.Vetayases@oracle.com 172712683SJimmy.Vetayases@oracle.com return (i); 172812683SJimmy.Vetayases@oracle.com } 172912683SJimmy.Vetayases@oracle.com 173012683SJimmy.Vetayases@oracle.com /* 173112683SJimmy.Vetayases@oracle.com * A rollback free for vectors allocated by apix_alloc_xxx(). 173212683SJimmy.Vetayases@oracle.com */ 173312683SJimmy.Vetayases@oracle.com void 173412683SJimmy.Vetayases@oracle.com apix_free_vectors(dev_info_t *dip, int inum, int count, int type) 173512683SJimmy.Vetayases@oracle.com { 173612683SJimmy.Vetayases@oracle.com int i, cpuid; 173712683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 173812683SJimmy.Vetayases@oracle.com 173912683SJimmy.Vetayases@oracle.com DDI_INTR_IMPLDBG((CE_CONT, "apix_free_vectors: dip: %p inum: %x " 174012683SJimmy.Vetayases@oracle.com "count: %x type: %x\n", 174112683SJimmy.Vetayases@oracle.com (void *)dip, inum, count, type)); 174212683SJimmy.Vetayases@oracle.com 174312683SJimmy.Vetayases@oracle.com lock_set(&apix_lock); 174412683SJimmy.Vetayases@oracle.com 174512683SJimmy.Vetayases@oracle.com for (i = 0; i < count; i++, inum++) { 174612683SJimmy.Vetayases@oracle.com if ((vecp = apix_get_dev_map(dip, inum, type)) == NULL) { 174712683SJimmy.Vetayases@oracle.com lock_clear(&apix_lock); 174812683SJimmy.Vetayases@oracle.com DDI_INTR_IMPLDBG((CE_CONT, "apix_free_vectors: " 174912683SJimmy.Vetayases@oracle.com "dip=0x%p inum=0x%x type=0x%x apix_find_intr() " 175012683SJimmy.Vetayases@oracle.com "failed\n", (void *)dip, inum, type)); 175112683SJimmy.Vetayases@oracle.com continue; 175212683SJimmy.Vetayases@oracle.com } 175312683SJimmy.Vetayases@oracle.com 175412683SJimmy.Vetayases@oracle.com APIX_ENTER_CPU_LOCK(vecp->v_cpuid); 175512683SJimmy.Vetayases@oracle.com cpuid = vecp->v_cpuid; 175612683SJimmy.Vetayases@oracle.com 175712683SJimmy.Vetayases@oracle.com DDI_INTR_IMPLDBG((CE_CONT, "apix_free_vectors: " 175812683SJimmy.Vetayases@oracle.com "dip=0x%p inum=0x%x type=0x%x vector 0x%x (share %d)\n", 175912683SJimmy.Vetayases@oracle.com (void *)dip, inum, type, vecp->v_vector, vecp->v_share)); 176012683SJimmy.Vetayases@oracle.com 176112683SJimmy.Vetayases@oracle.com /* tear down device interrupt to vector mapping */ 176212683SJimmy.Vetayases@oracle.com apix_clear_dev_map(dip, inum, type); 176312683SJimmy.Vetayases@oracle.com 176412683SJimmy.Vetayases@oracle.com if (vecp->v_type == APIX_TYPE_FIXED) { 176512683SJimmy.Vetayases@oracle.com if (vecp->v_share > 0) { /* share IRQ line */ 176612683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(cpuid); 176712683SJimmy.Vetayases@oracle.com continue; 176812683SJimmy.Vetayases@oracle.com } 176912683SJimmy.Vetayases@oracle.com 177012683SJimmy.Vetayases@oracle.com /* Free apic_irq_table entry */ 177112683SJimmy.Vetayases@oracle.com apix_intx_free(vecp->v_inum); 177212683SJimmy.Vetayases@oracle.com } 177312683SJimmy.Vetayases@oracle.com 177412683SJimmy.Vetayases@oracle.com /* free vector */ 177512683SJimmy.Vetayases@oracle.com apix_cleanup_vector(vecp); 177612683SJimmy.Vetayases@oracle.com 177712683SJimmy.Vetayases@oracle.com APIX_LEAVE_CPU_LOCK(cpuid); 177812683SJimmy.Vetayases@oracle.com } 177912683SJimmy.Vetayases@oracle.com 178012683SJimmy.Vetayases@oracle.com lock_clear(&apix_lock); 178112683SJimmy.Vetayases@oracle.com } 178212683SJimmy.Vetayases@oracle.com 178312683SJimmy.Vetayases@oracle.com /* 178412683SJimmy.Vetayases@oracle.com * Must be called with apix_lock held 178512683SJimmy.Vetayases@oracle.com */ 178612683SJimmy.Vetayases@oracle.com apix_vector_t * 178712683SJimmy.Vetayases@oracle.com apix_setup_io_intr(apix_vector_t *vecp) 178812683SJimmy.Vetayases@oracle.com { 178912683SJimmy.Vetayases@oracle.com processorid_t bindcpu; 179012683SJimmy.Vetayases@oracle.com int ret; 179112683SJimmy.Vetayases@oracle.com 179212683SJimmy.Vetayases@oracle.com ASSERT(LOCK_HELD(&apix_lock)); 179312683SJimmy.Vetayases@oracle.com 179412683SJimmy.Vetayases@oracle.com /* 179512683SJimmy.Vetayases@oracle.com * Interrupts are enabled on the CPU, programme IOAPIC RDT 179612683SJimmy.Vetayases@oracle.com * entry or MSI/X address/data to enable the interrupt. 179712683SJimmy.Vetayases@oracle.com */ 179812683SJimmy.Vetayases@oracle.com if (apix_is_cpu_enabled(vecp->v_cpuid)) { 179912683SJimmy.Vetayases@oracle.com apix_enable_vector(vecp); 180012683SJimmy.Vetayases@oracle.com return (vecp); 180112683SJimmy.Vetayases@oracle.com } 180212683SJimmy.Vetayases@oracle.com 180312683SJimmy.Vetayases@oracle.com /* 180412683SJimmy.Vetayases@oracle.com * CPU is not up or interrupts are disabled. Fall back to the 180512683SJimmy.Vetayases@oracle.com * first avialable CPU. 180612683SJimmy.Vetayases@oracle.com */ 180712683SJimmy.Vetayases@oracle.com bindcpu = apic_find_cpu(APIC_CPU_INTR_ENABLE); 180812683SJimmy.Vetayases@oracle.com 180912683SJimmy.Vetayases@oracle.com if (vecp->v_type == APIX_TYPE_MSI) 181012683SJimmy.Vetayases@oracle.com return (apix_grp_set_cpu(vecp, bindcpu, &ret)); 181112683SJimmy.Vetayases@oracle.com 181212683SJimmy.Vetayases@oracle.com return (apix_set_cpu(vecp, bindcpu, &ret)); 181312683SJimmy.Vetayases@oracle.com } 181412683SJimmy.Vetayases@oracle.com 181512683SJimmy.Vetayases@oracle.com /* 181612683SJimmy.Vetayases@oracle.com * For interrupts which call add_avintr() before apic is initialized. 181712683SJimmy.Vetayases@oracle.com * ioapix_setup_intr() will 181812683SJimmy.Vetayases@oracle.com * - allocate vector 181912683SJimmy.Vetayases@oracle.com * - copy over ISR 182012683SJimmy.Vetayases@oracle.com */ 182112683SJimmy.Vetayases@oracle.com static void 182212683SJimmy.Vetayases@oracle.com ioapix_setup_intr(int irqno, iflag_t *flagp) 182312683SJimmy.Vetayases@oracle.com { 182412683SJimmy.Vetayases@oracle.com extern struct av_head autovect[]; 182512683SJimmy.Vetayases@oracle.com apix_vector_t *vecp; 182612683SJimmy.Vetayases@oracle.com apic_irq_t *irqp; 182712683SJimmy.Vetayases@oracle.com uchar_t ioapicindex, ipin; 182812683SJimmy.Vetayases@oracle.com ulong_t iflag; 182912683SJimmy.Vetayases@oracle.com struct autovec *avp; 183012683SJimmy.Vetayases@oracle.com 183112683SJimmy.Vetayases@oracle.com irqp = apic_irq_table[irqno]; 183212683SJimmy.Vetayases@oracle.com ioapicindex = acpi_find_ioapic(irqno); 183312683SJimmy.Vetayases@oracle.com ASSERT(ioapicindex != 0xFF); 183412683SJimmy.Vetayases@oracle.com ipin = irqno - apic_io_vectbase[ioapicindex]; 183512683SJimmy.Vetayases@oracle.com 183612683SJimmy.Vetayases@oracle.com if ((irqp != NULL) && (irqp->airq_mps_intr_index == ACPI_INDEX)) { 183712683SJimmy.Vetayases@oracle.com ASSERT(irqp->airq_intin_no == ipin && 183812683SJimmy.Vetayases@oracle.com irqp->airq_ioapicindex == ioapicindex); 183912683SJimmy.Vetayases@oracle.com vecp = xv_vector(irqp->airq_cpu, irqp->airq_vector); 184012683SJimmy.Vetayases@oracle.com ASSERT(!IS_VECT_FREE(vecp)); 184112683SJimmy.Vetayases@oracle.com } else { 184212683SJimmy.Vetayases@oracle.com vecp = apix_alloc_intx(NULL, 0, irqno); 184312683SJimmy.Vetayases@oracle.com 184412683SJimmy.Vetayases@oracle.com irqp = apic_irq_table[irqno]; 184512683SJimmy.Vetayases@oracle.com irqp->airq_mps_intr_index = ACPI_INDEX; 184612683SJimmy.Vetayases@oracle.com irqp->airq_ioapicindex = ioapicindex; 184712683SJimmy.Vetayases@oracle.com irqp->airq_intin_no = ipin; 184812683SJimmy.Vetayases@oracle.com irqp->airq_iflag = *flagp; 184912683SJimmy.Vetayases@oracle.com irqp->airq_share++; 185012683SJimmy.Vetayases@oracle.com apic_record_rdt_entry(irqp, irqno); 185112683SJimmy.Vetayases@oracle.com } 185212683SJimmy.Vetayases@oracle.com 185312683SJimmy.Vetayases@oracle.com /* copy over autovect */ 185412683SJimmy.Vetayases@oracle.com for (avp = autovect[irqno].avh_link; avp; avp = avp->av_link) 185512683SJimmy.Vetayases@oracle.com apix_insert_av(vecp, avp->av_intr_id, avp->av_vector, 185612683SJimmy.Vetayases@oracle.com avp->av_intarg1, avp->av_intarg2, avp->av_ticksp, 185712683SJimmy.Vetayases@oracle.com avp->av_prilevel, avp->av_dip); 185812683SJimmy.Vetayases@oracle.com 185912683SJimmy.Vetayases@oracle.com /* Program I/O APIC */ 186012683SJimmy.Vetayases@oracle.com iflag = intr_clear(); 186112683SJimmy.Vetayases@oracle.com lock_set(&apix_lock); 186212683SJimmy.Vetayases@oracle.com 186312683SJimmy.Vetayases@oracle.com (void) apix_setup_io_intr(vecp); 186412683SJimmy.Vetayases@oracle.com 186512683SJimmy.Vetayases@oracle.com lock_clear(&apix_lock); 186612683SJimmy.Vetayases@oracle.com intr_restore(iflag); 186712683SJimmy.Vetayases@oracle.com 186812683SJimmy.Vetayases@oracle.com APIC_VERBOSE_IOAPIC((CE_CONT, "apix: setup ioapic, irqno %x " 186912683SJimmy.Vetayases@oracle.com "(ioapic %x, ipin %x) is bound to cpu %x, vector %x\n", 187012683SJimmy.Vetayases@oracle.com irqno, ioapicindex, ipin, irqp->airq_cpu, irqp->airq_vector)); 187112683SJimmy.Vetayases@oracle.com } 187212683SJimmy.Vetayases@oracle.com 187312683SJimmy.Vetayases@oracle.com void 187412683SJimmy.Vetayases@oracle.com ioapix_init_intr(int mask_apic) 187512683SJimmy.Vetayases@oracle.com { 187612683SJimmy.Vetayases@oracle.com int ioapicindex; 187712683SJimmy.Vetayases@oracle.com int i, j; 187812683SJimmy.Vetayases@oracle.com 187912683SJimmy.Vetayases@oracle.com /* mask interrupt vectors */ 188012683SJimmy.Vetayases@oracle.com for (j = 0; j < apic_io_max && mask_apic; j++) { 188112683SJimmy.Vetayases@oracle.com int intin_max; 188212683SJimmy.Vetayases@oracle.com 188312683SJimmy.Vetayases@oracle.com ioapicindex = j; 188412683SJimmy.Vetayases@oracle.com /* Bits 23-16 define the maximum redirection entries */ 188512683SJimmy.Vetayases@oracle.com intin_max = (ioapic_read(ioapicindex, APIC_VERS_CMD) >> 16) 188612683SJimmy.Vetayases@oracle.com & 0xff; 188712683SJimmy.Vetayases@oracle.com for (i = 0; i <= intin_max; i++) 188812683SJimmy.Vetayases@oracle.com ioapic_write(ioapicindex, APIC_RDT_CMD + 2 * i, 188912683SJimmy.Vetayases@oracle.com AV_MASK); 189012683SJimmy.Vetayases@oracle.com } 189112683SJimmy.Vetayases@oracle.com 189212683SJimmy.Vetayases@oracle.com /* 189312683SJimmy.Vetayases@oracle.com * Hack alert: deal with ACPI SCI interrupt chicken/egg here 189412683SJimmy.Vetayases@oracle.com */ 189512683SJimmy.Vetayases@oracle.com if (apic_sci_vect > 0) 189612683SJimmy.Vetayases@oracle.com ioapix_setup_intr(apic_sci_vect, &apic_sci_flags); 189712683SJimmy.Vetayases@oracle.com 189812683SJimmy.Vetayases@oracle.com /* 189912683SJimmy.Vetayases@oracle.com * Hack alert: deal with ACPI HPET interrupt chicken/egg here. 190012683SJimmy.Vetayases@oracle.com */ 190112683SJimmy.Vetayases@oracle.com if (apic_hpet_vect > 0) 190212683SJimmy.Vetayases@oracle.com ioapix_setup_intr(apic_hpet_vect, &apic_hpet_flags); 190312683SJimmy.Vetayases@oracle.com } 1904