111600SVikram.Hegde@Sun.COM /* 211600SVikram.Hegde@Sun.COM * CDDL HEADER START 311600SVikram.Hegde@Sun.COM * 411600SVikram.Hegde@Sun.COM * The contents of this file are subject to the terms of the 511600SVikram.Hegde@Sun.COM * Common Development and Distribution License (the "License"). 611600SVikram.Hegde@Sun.COM * You may not use this file except in compliance with the License. 711600SVikram.Hegde@Sun.COM * 811600SVikram.Hegde@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 911600SVikram.Hegde@Sun.COM * or http://www.opensolaris.org/os/licensing. 1011600SVikram.Hegde@Sun.COM * See the License for the specific language governing permissions 1111600SVikram.Hegde@Sun.COM * and limitations under the License. 1211600SVikram.Hegde@Sun.COM * 1311600SVikram.Hegde@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 1411600SVikram.Hegde@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1511600SVikram.Hegde@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 1611600SVikram.Hegde@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 1711600SVikram.Hegde@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 1811600SVikram.Hegde@Sun.COM * 1911600SVikram.Hegde@Sun.COM * CDDL HEADER END 2011600SVikram.Hegde@Sun.COM */ 2111600SVikram.Hegde@Sun.COM 2211600SVikram.Hegde@Sun.COM /* 2312683SJimmy.Vetayases@oracle.com * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 2411600SVikram.Hegde@Sun.COM */ 2511600SVikram.Hegde@Sun.COM 2611600SVikram.Hegde@Sun.COM /* 2711600SVikram.Hegde@Sun.COM * Copyright (c) 2009, Intel Corporation. 2811600SVikram.Hegde@Sun.COM * All rights reserved. 2911600SVikram.Hegde@Sun.COM */ 3011600SVikram.Hegde@Sun.COM 3111600SVikram.Hegde@Sun.COM 3211600SVikram.Hegde@Sun.COM #include <sys/apic.h> 3311600SVikram.Hegde@Sun.COM #include <vm/hat_i86.h> 3411600SVikram.Hegde@Sun.COM #include <sys/sysmacros.h> 3511600SVikram.Hegde@Sun.COM #include <sys/smp_impldefs.h> 3611600SVikram.Hegde@Sun.COM #include <sys/immu.h> 3711600SVikram.Hegde@Sun.COM 3811600SVikram.Hegde@Sun.COM 3911600SVikram.Hegde@Sun.COM typedef struct intrmap_private { 4011600SVikram.Hegde@Sun.COM immu_t *ir_immu; 4111600SVikram.Hegde@Sun.COM uint16_t ir_idx; 4211600SVikram.Hegde@Sun.COM uint32_t ir_sid_svt_sq; 4311600SVikram.Hegde@Sun.COM } intrmap_private_t; 4411600SVikram.Hegde@Sun.COM 4512683SJimmy.Vetayases@oracle.com #define INTRMAP_PRIVATE(intrmap) ((intrmap_private_t *)intrmap) 4611600SVikram.Hegde@Sun.COM 4711600SVikram.Hegde@Sun.COM /* interrupt remapping table entry */ 4811600SVikram.Hegde@Sun.COM typedef struct intrmap_rte { 4911600SVikram.Hegde@Sun.COM uint64_t lo; 5011600SVikram.Hegde@Sun.COM uint64_t hi; 5111600SVikram.Hegde@Sun.COM } intrmap_rte_t; 5211600SVikram.Hegde@Sun.COM 5311600SVikram.Hegde@Sun.COM #define IRTE_HIGH(sid_svt_sq) (sid_svt_sq) 5411600SVikram.Hegde@Sun.COM #define IRTE_LOW(dst, vector, dlm, tm, rh, dm, fpd, p) \ 5511600SVikram.Hegde@Sun.COM (((uint64_t)(dst) << 32) | \ 5611600SVikram.Hegde@Sun.COM ((uint64_t)(vector) << 16) | \ 5711600SVikram.Hegde@Sun.COM ((uint64_t)(dlm) << 5) | \ 5811600SVikram.Hegde@Sun.COM ((uint64_t)(tm) << 4) | \ 5911600SVikram.Hegde@Sun.COM ((uint64_t)(rh) << 3) | \ 6011600SVikram.Hegde@Sun.COM ((uint64_t)(dm) << 2) | \ 6111600SVikram.Hegde@Sun.COM ((uint64_t)(fpd) << 1) | \ 6211600SVikram.Hegde@Sun.COM (p)) 6311600SVikram.Hegde@Sun.COM 6411600SVikram.Hegde@Sun.COM typedef enum { 6511600SVikram.Hegde@Sun.COM SVT_NO_VERIFY = 0, /* no verification */ 6611600SVikram.Hegde@Sun.COM SVT_ALL_VERIFY, /* using sid and sq to verify */ 6711600SVikram.Hegde@Sun.COM SVT_BUS_VERIFY, /* verify #startbus and #endbus */ 6811600SVikram.Hegde@Sun.COM SVT_RSVD 6911600SVikram.Hegde@Sun.COM } intrmap_svt_t; 7011600SVikram.Hegde@Sun.COM 7111600SVikram.Hegde@Sun.COM typedef enum { 7211600SVikram.Hegde@Sun.COM SQ_VERIFY_ALL = 0, /* verify all 16 bits */ 7311600SVikram.Hegde@Sun.COM SQ_VERIFY_IGR_1, /* ignore bit 3 */ 7411600SVikram.Hegde@Sun.COM SQ_VERIFY_IGR_2, /* ignore bit 2-3 */ 7511600SVikram.Hegde@Sun.COM SQ_VERIFY_IGR_3 /* ignore bit 1-3 */ 7611600SVikram.Hegde@Sun.COM } intrmap_sq_t; 7711600SVikram.Hegde@Sun.COM 7811600SVikram.Hegde@Sun.COM /* 7911600SVikram.Hegde@Sun.COM * S field of the Interrupt Remapping Table Address Register 8011600SVikram.Hegde@Sun.COM * the size of the interrupt remapping table is 1 << (immu_intrmap_irta_s + 1) 8111600SVikram.Hegde@Sun.COM */ 8211600SVikram.Hegde@Sun.COM static uint_t intrmap_irta_s = INTRMAP_MAX_IRTA_SIZE; 8311600SVikram.Hegde@Sun.COM 8411600SVikram.Hegde@Sun.COM /* 8511600SVikram.Hegde@Sun.COM * If true, arrange to suppress broadcast EOI by setting edge-triggered mode 8611600SVikram.Hegde@Sun.COM * even for level-triggered interrupts in the interrupt-remapping engine. 8711600SVikram.Hegde@Sun.COM * If false, broadcast EOI can still be suppressed if the CPU supports the 8811600SVikram.Hegde@Sun.COM * APIC_SVR_SUPPRESS_BROADCAST_EOI bit. In both cases, the IOAPIC is still 8911600SVikram.Hegde@Sun.COM * programmed with the correct trigger mode, and pcplusmp must send an EOI 9011600SVikram.Hegde@Sun.COM * to the IOAPIC by writing to the IOAPIC's EOI register to make up for the 9111600SVikram.Hegde@Sun.COM * missing broadcast EOI. 9211600SVikram.Hegde@Sun.COM */ 9311600SVikram.Hegde@Sun.COM static int intrmap_suppress_brdcst_eoi = 0; 9411600SVikram.Hegde@Sun.COM 9511600SVikram.Hegde@Sun.COM /* 9611600SVikram.Hegde@Sun.COM * whether verify the source id of interrupt request 9711600SVikram.Hegde@Sun.COM */ 9811600SVikram.Hegde@Sun.COM static int intrmap_enable_sid_verify = 0; 9911600SVikram.Hegde@Sun.COM 10011600SVikram.Hegde@Sun.COM /* fault types for DVMA remapping */ 10111600SVikram.Hegde@Sun.COM static char *immu_dvma_faults[] = { 10211600SVikram.Hegde@Sun.COM "Reserved", 10311600SVikram.Hegde@Sun.COM "The present field in root-entry is Clear", 10411600SVikram.Hegde@Sun.COM "The present field in context-entry is Clear", 10511600SVikram.Hegde@Sun.COM "Hardware detected invalid programming of a context-entry", 10611600SVikram.Hegde@Sun.COM "The DMA request attempted to access an address beyond max support", 10711600SVikram.Hegde@Sun.COM "The Write field in a page-table entry is Clear when DMA write", 10811600SVikram.Hegde@Sun.COM "The Read field in a page-table entry is Clear when DMA read", 10911600SVikram.Hegde@Sun.COM "Access the next level page table resulted in error", 11011600SVikram.Hegde@Sun.COM "Access the root-entry table resulted in error", 11111600SVikram.Hegde@Sun.COM "Access the context-entry table resulted in error", 11211600SVikram.Hegde@Sun.COM "Reserved field not initialized to zero in a present root-entry", 11311600SVikram.Hegde@Sun.COM "Reserved field not initialized to zero in a present context-entry", 11411600SVikram.Hegde@Sun.COM "Reserved field not initialized to zero in a present page-table entry", 11511600SVikram.Hegde@Sun.COM "DMA blocked due to the Translation Type field in context-entry", 11611600SVikram.Hegde@Sun.COM "Incorrect fault event reason number", 11711600SVikram.Hegde@Sun.COM }; 11811600SVikram.Hegde@Sun.COM #define DVMA_MAX_FAULTS (sizeof (immu_dvma_faults)/(sizeof (char *))) - 1 11911600SVikram.Hegde@Sun.COM 12011600SVikram.Hegde@Sun.COM /* fault types for interrupt remapping */ 12111600SVikram.Hegde@Sun.COM static char *immu_intrmap_faults[] = { 12211600SVikram.Hegde@Sun.COM "reserved field set in IRTE", 12311600SVikram.Hegde@Sun.COM "interrupt_index exceed the intr-remap table size", 12411600SVikram.Hegde@Sun.COM "present field in IRTE is clear", 12511600SVikram.Hegde@Sun.COM "hardware access intr-remap table address resulted in error", 12611600SVikram.Hegde@Sun.COM "reserved field set in IRTE, include various conditional", 12711600SVikram.Hegde@Sun.COM "hardware blocked an interrupt request in Compatibility format", 12811600SVikram.Hegde@Sun.COM "remappable interrupt request blocked due to verification failure" 12911600SVikram.Hegde@Sun.COM }; 13011600SVikram.Hegde@Sun.COM #define INTRMAP_MAX_FAULTS \ 13111600SVikram.Hegde@Sun.COM (sizeof (immu_intrmap_faults) / (sizeof (char *))) - 1 13211600SVikram.Hegde@Sun.COM 13311600SVikram.Hegde@Sun.COM /* Function prototypes */ 13411600SVikram.Hegde@Sun.COM static int immu_intrmap_init(int apic_mode); 13511600SVikram.Hegde@Sun.COM static void immu_intrmap_switchon(int suppress_brdcst_eoi); 13612683SJimmy.Vetayases@oracle.com static void immu_intrmap_alloc(void **intrmap_private_tbl, dev_info_t *dip, 13712683SJimmy.Vetayases@oracle.com uint16_t type, int count, uchar_t ioapic_index); 13812683SJimmy.Vetayases@oracle.com static void immu_intrmap_map(void *intrmap_private, void *intrmap_data, 13912683SJimmy.Vetayases@oracle.com uint16_t type, int count); 14012683SJimmy.Vetayases@oracle.com static void immu_intrmap_free(void **intrmap_privatep); 14112683SJimmy.Vetayases@oracle.com static void immu_intrmap_rdt(void *intrmap_private, ioapic_rdt_t *irdt); 14212683SJimmy.Vetayases@oracle.com static void immu_intrmap_msi(void *intrmap_private, msi_regs_t *mregs); 14311600SVikram.Hegde@Sun.COM 14411600SVikram.Hegde@Sun.COM static struct apic_intrmap_ops intrmap_ops = { 14511600SVikram.Hegde@Sun.COM immu_intrmap_init, 14611600SVikram.Hegde@Sun.COM immu_intrmap_switchon, 14711600SVikram.Hegde@Sun.COM immu_intrmap_alloc, 14811600SVikram.Hegde@Sun.COM immu_intrmap_map, 14911600SVikram.Hegde@Sun.COM immu_intrmap_free, 15011600SVikram.Hegde@Sun.COM immu_intrmap_rdt, 15111600SVikram.Hegde@Sun.COM immu_intrmap_msi, 15211600SVikram.Hegde@Sun.COM }; 15311600SVikram.Hegde@Sun.COM 15411600SVikram.Hegde@Sun.COM /* apic mode, APIC/X2APIC */ 15511600SVikram.Hegde@Sun.COM static int intrmap_apic_mode = LOCAL_APIC; 15611600SVikram.Hegde@Sun.COM 15711600SVikram.Hegde@Sun.COM 15811600SVikram.Hegde@Sun.COM /* 15911600SVikram.Hegde@Sun.COM * helper functions 16011600SVikram.Hegde@Sun.COM */ 16111600SVikram.Hegde@Sun.COM static uint_t 16211600SVikram.Hegde@Sun.COM bitset_find_free(bitset_t *b, uint_t post) 16311600SVikram.Hegde@Sun.COM { 16411600SVikram.Hegde@Sun.COM uint_t i; 16511600SVikram.Hegde@Sun.COM uint_t cap = bitset_capacity(b); 16611600SVikram.Hegde@Sun.COM 16711600SVikram.Hegde@Sun.COM if (post == cap) 16811600SVikram.Hegde@Sun.COM post = 0; 16911600SVikram.Hegde@Sun.COM 17011600SVikram.Hegde@Sun.COM ASSERT(post < cap); 17111600SVikram.Hegde@Sun.COM 17211600SVikram.Hegde@Sun.COM for (i = post; i < cap; i++) { 17311600SVikram.Hegde@Sun.COM if (!bitset_in_set(b, i)) 17411600SVikram.Hegde@Sun.COM return (i); 17511600SVikram.Hegde@Sun.COM } 17611600SVikram.Hegde@Sun.COM 17711600SVikram.Hegde@Sun.COM for (i = 0; i < post; i++) { 17811600SVikram.Hegde@Sun.COM if (!bitset_in_set(b, i)) 17911600SVikram.Hegde@Sun.COM return (i); 18011600SVikram.Hegde@Sun.COM } 18111600SVikram.Hegde@Sun.COM 18211600SVikram.Hegde@Sun.COM return (INTRMAP_IDX_FULL); /* no free index */ 18311600SVikram.Hegde@Sun.COM } 18411600SVikram.Hegde@Sun.COM 18511600SVikram.Hegde@Sun.COM /* 18611600SVikram.Hegde@Sun.COM * helper function to find 'count' contigous free 18711600SVikram.Hegde@Sun.COM * interrupt remapping table entries 18811600SVikram.Hegde@Sun.COM */ 18911600SVikram.Hegde@Sun.COM static uint_t 19011600SVikram.Hegde@Sun.COM bitset_find_multi_free(bitset_t *b, uint_t post, uint_t count) 19111600SVikram.Hegde@Sun.COM { 19211600SVikram.Hegde@Sun.COM uint_t i, j; 19311600SVikram.Hegde@Sun.COM uint_t cap = bitset_capacity(b); 19411600SVikram.Hegde@Sun.COM 19511600SVikram.Hegde@Sun.COM if (post == INTRMAP_IDX_FULL) { 19611600SVikram.Hegde@Sun.COM return (INTRMAP_IDX_FULL); 19711600SVikram.Hegde@Sun.COM } 19811600SVikram.Hegde@Sun.COM 19911600SVikram.Hegde@Sun.COM if (count > cap) 20011600SVikram.Hegde@Sun.COM return (INTRMAP_IDX_FULL); 20111600SVikram.Hegde@Sun.COM 20211600SVikram.Hegde@Sun.COM ASSERT(post < cap); 20311600SVikram.Hegde@Sun.COM 20411600SVikram.Hegde@Sun.COM for (i = post; (i + count) <= cap; i++) { 20511600SVikram.Hegde@Sun.COM for (j = 0; j < count; j++) { 20611600SVikram.Hegde@Sun.COM if (bitset_in_set(b, (i + j))) { 20711600SVikram.Hegde@Sun.COM i = i + j; 20811600SVikram.Hegde@Sun.COM break; 20911600SVikram.Hegde@Sun.COM } 21011600SVikram.Hegde@Sun.COM if (j == count - 1) 21111600SVikram.Hegde@Sun.COM return (i); 21211600SVikram.Hegde@Sun.COM } 21311600SVikram.Hegde@Sun.COM } 21411600SVikram.Hegde@Sun.COM 21511600SVikram.Hegde@Sun.COM for (i = 0; (i < post) && ((i + count) <= cap); i++) { 21611600SVikram.Hegde@Sun.COM for (j = 0; j < count; j++) { 21711600SVikram.Hegde@Sun.COM if (bitset_in_set(b, (i + j))) { 21811600SVikram.Hegde@Sun.COM i = i + j; 21911600SVikram.Hegde@Sun.COM break; 22011600SVikram.Hegde@Sun.COM } 22111600SVikram.Hegde@Sun.COM if (j == count - 1) 22211600SVikram.Hegde@Sun.COM return (i); 22311600SVikram.Hegde@Sun.COM } 22411600SVikram.Hegde@Sun.COM } 22511600SVikram.Hegde@Sun.COM 22611600SVikram.Hegde@Sun.COM return (INTRMAP_IDX_FULL); /* no free index */ 22711600SVikram.Hegde@Sun.COM } 22811600SVikram.Hegde@Sun.COM 22911600SVikram.Hegde@Sun.COM /* alloc one interrupt remapping table entry */ 23011600SVikram.Hegde@Sun.COM static int 23111600SVikram.Hegde@Sun.COM alloc_tbl_entry(intrmap_t *intrmap) 23211600SVikram.Hegde@Sun.COM { 23311600SVikram.Hegde@Sun.COM uint32_t idx; 23411600SVikram.Hegde@Sun.COM 23511600SVikram.Hegde@Sun.COM for (;;) { 23611600SVikram.Hegde@Sun.COM mutex_enter(&intrmap->intrmap_lock); 23711600SVikram.Hegde@Sun.COM idx = intrmap->intrmap_free; 23811600SVikram.Hegde@Sun.COM if (idx != INTRMAP_IDX_FULL) { 23911600SVikram.Hegde@Sun.COM bitset_add(&intrmap->intrmap_map, idx); 24011600SVikram.Hegde@Sun.COM intrmap->intrmap_free = 24111600SVikram.Hegde@Sun.COM bitset_find_free(&intrmap->intrmap_map, idx + 1); 24211600SVikram.Hegde@Sun.COM mutex_exit(&intrmap->intrmap_lock); 24311600SVikram.Hegde@Sun.COM break; 24411600SVikram.Hegde@Sun.COM } 24511600SVikram.Hegde@Sun.COM 24611600SVikram.Hegde@Sun.COM /* no free intr entry, use compatible format intr */ 24711600SVikram.Hegde@Sun.COM mutex_exit(&intrmap->intrmap_lock); 24811600SVikram.Hegde@Sun.COM 24911600SVikram.Hegde@Sun.COM if (intrmap_apic_mode != LOCAL_X2APIC) { 25011600SVikram.Hegde@Sun.COM break; 25111600SVikram.Hegde@Sun.COM } 25211600SVikram.Hegde@Sun.COM 25311600SVikram.Hegde@Sun.COM /* 25411600SVikram.Hegde@Sun.COM * x2apic mode not allowed compatible 25511600SVikram.Hegde@Sun.COM * interrupt 25611600SVikram.Hegde@Sun.COM */ 25711600SVikram.Hegde@Sun.COM delay(IMMU_ALLOC_RESOURCE_DELAY); 25811600SVikram.Hegde@Sun.COM } 25911600SVikram.Hegde@Sun.COM 26011600SVikram.Hegde@Sun.COM return (idx); 26111600SVikram.Hegde@Sun.COM } 26211600SVikram.Hegde@Sun.COM 26311600SVikram.Hegde@Sun.COM /* alloc 'cnt' contigous interrupt remapping table entries */ 26411600SVikram.Hegde@Sun.COM static int 26511600SVikram.Hegde@Sun.COM alloc_tbl_multi_entries(intrmap_t *intrmap, uint_t cnt) 26611600SVikram.Hegde@Sun.COM { 26711600SVikram.Hegde@Sun.COM uint_t idx, pos, i; 26811600SVikram.Hegde@Sun.COM 26911600SVikram.Hegde@Sun.COM for (; ; ) { 27011600SVikram.Hegde@Sun.COM mutex_enter(&intrmap->intrmap_lock); 27111600SVikram.Hegde@Sun.COM pos = intrmap->intrmap_free; 27211600SVikram.Hegde@Sun.COM idx = bitset_find_multi_free(&intrmap->intrmap_map, pos, cnt); 27311600SVikram.Hegde@Sun.COM 27411600SVikram.Hegde@Sun.COM if (idx != INTRMAP_IDX_FULL) { 27511600SVikram.Hegde@Sun.COM if (idx <= pos && pos < (idx + cnt)) { 27611600SVikram.Hegde@Sun.COM intrmap->intrmap_free = bitset_find_free( 27711600SVikram.Hegde@Sun.COM &intrmap->intrmap_map, idx + cnt); 27811600SVikram.Hegde@Sun.COM } 27911600SVikram.Hegde@Sun.COM for (i = 0; i < cnt; i++) { 28011600SVikram.Hegde@Sun.COM bitset_add(&intrmap->intrmap_map, idx + i); 28111600SVikram.Hegde@Sun.COM } 28211600SVikram.Hegde@Sun.COM mutex_exit(&intrmap->intrmap_lock); 283*12716Sfrank.van.der.linden@oracle.com break; 28411600SVikram.Hegde@Sun.COM } 28511600SVikram.Hegde@Sun.COM 28611600SVikram.Hegde@Sun.COM mutex_exit(&intrmap->intrmap_lock); 28711600SVikram.Hegde@Sun.COM 28811600SVikram.Hegde@Sun.COM if (intrmap_apic_mode != LOCAL_X2APIC) { 28911600SVikram.Hegde@Sun.COM break; 29011600SVikram.Hegde@Sun.COM } 29111600SVikram.Hegde@Sun.COM 29211600SVikram.Hegde@Sun.COM /* x2apic mode not allowed comapitible interrupt */ 29311600SVikram.Hegde@Sun.COM delay(IMMU_ALLOC_RESOURCE_DELAY); 29411600SVikram.Hegde@Sun.COM } 29511600SVikram.Hegde@Sun.COM 29611600SVikram.Hegde@Sun.COM return (idx); 29711600SVikram.Hegde@Sun.COM } 29811600SVikram.Hegde@Sun.COM 29911600SVikram.Hegde@Sun.COM /* init interrupt remapping table */ 30011600SVikram.Hegde@Sun.COM static int 30111600SVikram.Hegde@Sun.COM init_unit(immu_t *immu) 30211600SVikram.Hegde@Sun.COM { 30311600SVikram.Hegde@Sun.COM intrmap_t *intrmap; 30411600SVikram.Hegde@Sun.COM size_t size; 30511600SVikram.Hegde@Sun.COM 30611600SVikram.Hegde@Sun.COM ddi_dma_attr_t intrmap_dma_attr = { 30711600SVikram.Hegde@Sun.COM DMA_ATTR_V0, 30811600SVikram.Hegde@Sun.COM 0U, 309*12716Sfrank.van.der.linden@oracle.com 0xffffffffffffffffULL, 31011600SVikram.Hegde@Sun.COM 0xffffffffU, 31111600SVikram.Hegde@Sun.COM MMU_PAGESIZE, /* page aligned */ 31211600SVikram.Hegde@Sun.COM 0x1, 31311600SVikram.Hegde@Sun.COM 0x1, 31411600SVikram.Hegde@Sun.COM 0xffffffffU, 315*12716Sfrank.van.der.linden@oracle.com 0xffffffffffffffffULL, 31611600SVikram.Hegde@Sun.COM 1, 31711600SVikram.Hegde@Sun.COM 4, 31811600SVikram.Hegde@Sun.COM 0 31911600SVikram.Hegde@Sun.COM }; 32011600SVikram.Hegde@Sun.COM 32111600SVikram.Hegde@Sun.COM ddi_device_acc_attr_t intrmap_acc_attr = { 32211600SVikram.Hegde@Sun.COM DDI_DEVICE_ATTR_V0, 32311600SVikram.Hegde@Sun.COM DDI_NEVERSWAP_ACC, 32411600SVikram.Hegde@Sun.COM DDI_STRICTORDER_ACC 32511600SVikram.Hegde@Sun.COM }; 32611600SVikram.Hegde@Sun.COM 32712513Sfrank.van.der.linden@oracle.com /* 32812513Sfrank.van.der.linden@oracle.com * Using interrupt remapping implies using the queue 32912513Sfrank.van.der.linden@oracle.com * invalidation interface. According to Intel, 33012513Sfrank.van.der.linden@oracle.com * hardware that supports interrupt remapping should 33112513Sfrank.van.der.linden@oracle.com * also support QI. 33212513Sfrank.van.der.linden@oracle.com */ 33312513Sfrank.van.der.linden@oracle.com ASSERT(IMMU_ECAP_GET_QI(immu->immu_regs_excap)); 33412513Sfrank.van.der.linden@oracle.com 33511600SVikram.Hegde@Sun.COM if (intrmap_apic_mode == LOCAL_X2APIC) { 33611600SVikram.Hegde@Sun.COM if (!IMMU_ECAP_GET_EIM(immu->immu_regs_excap)) { 33711600SVikram.Hegde@Sun.COM return (DDI_FAILURE); 33811600SVikram.Hegde@Sun.COM } 33911600SVikram.Hegde@Sun.COM } 34011600SVikram.Hegde@Sun.COM 34111600SVikram.Hegde@Sun.COM if (intrmap_irta_s > INTRMAP_MAX_IRTA_SIZE) { 34211600SVikram.Hegde@Sun.COM intrmap_irta_s = INTRMAP_MAX_IRTA_SIZE; 34311600SVikram.Hegde@Sun.COM } 34411600SVikram.Hegde@Sun.COM 34511600SVikram.Hegde@Sun.COM intrmap = kmem_zalloc(sizeof (intrmap_t), KM_SLEEP); 34611600SVikram.Hegde@Sun.COM 34711600SVikram.Hegde@Sun.COM if (ddi_dma_alloc_handle(immu->immu_dip, 34811600SVikram.Hegde@Sun.COM &intrmap_dma_attr, 34911600SVikram.Hegde@Sun.COM DDI_DMA_SLEEP, 35011600SVikram.Hegde@Sun.COM NULL, 35111600SVikram.Hegde@Sun.COM &(intrmap->intrmap_dma_hdl)) != DDI_SUCCESS) { 35211600SVikram.Hegde@Sun.COM kmem_free(intrmap, sizeof (intrmap_t)); 35311600SVikram.Hegde@Sun.COM return (DDI_FAILURE); 35411600SVikram.Hegde@Sun.COM } 35511600SVikram.Hegde@Sun.COM 35611600SVikram.Hegde@Sun.COM intrmap->intrmap_size = 1 << (intrmap_irta_s + 1); 35711600SVikram.Hegde@Sun.COM size = intrmap->intrmap_size * INTRMAP_RTE_SIZE; 35811600SVikram.Hegde@Sun.COM if (ddi_dma_mem_alloc(intrmap->intrmap_dma_hdl, 35911600SVikram.Hegde@Sun.COM size, 36011600SVikram.Hegde@Sun.COM &intrmap_acc_attr, 36111600SVikram.Hegde@Sun.COM DDI_DMA_CONSISTENT | IOMEM_DATA_UNCACHED, 36211600SVikram.Hegde@Sun.COM DDI_DMA_SLEEP, 36311600SVikram.Hegde@Sun.COM NULL, 36411600SVikram.Hegde@Sun.COM &(intrmap->intrmap_vaddr), 36511600SVikram.Hegde@Sun.COM &size, 36611600SVikram.Hegde@Sun.COM &(intrmap->intrmap_acc_hdl)) != DDI_SUCCESS) { 36711600SVikram.Hegde@Sun.COM ddi_dma_free_handle(&(intrmap->intrmap_dma_hdl)); 36811600SVikram.Hegde@Sun.COM kmem_free(intrmap, sizeof (intrmap_t)); 36911600SVikram.Hegde@Sun.COM return (DDI_FAILURE); 37011600SVikram.Hegde@Sun.COM } 37111600SVikram.Hegde@Sun.COM 37211600SVikram.Hegde@Sun.COM ASSERT(!((uintptr_t)intrmap->intrmap_vaddr & MMU_PAGEOFFSET)); 37311600SVikram.Hegde@Sun.COM bzero(intrmap->intrmap_vaddr, size); 37411600SVikram.Hegde@Sun.COM intrmap->intrmap_paddr = pfn_to_pa( 37511600SVikram.Hegde@Sun.COM hat_getpfnum(kas.a_hat, intrmap->intrmap_vaddr)); 37611600SVikram.Hegde@Sun.COM 37711600SVikram.Hegde@Sun.COM mutex_init(&(intrmap->intrmap_lock), NULL, MUTEX_DRIVER, NULL); 37811600SVikram.Hegde@Sun.COM bitset_init(&intrmap->intrmap_map); 37911600SVikram.Hegde@Sun.COM bitset_resize(&intrmap->intrmap_map, intrmap->intrmap_size); 38011600SVikram.Hegde@Sun.COM intrmap->intrmap_free = 0; 38111600SVikram.Hegde@Sun.COM 38211600SVikram.Hegde@Sun.COM immu->immu_intrmap = intrmap; 38311600SVikram.Hegde@Sun.COM 38411600SVikram.Hegde@Sun.COM return (DDI_SUCCESS); 38511600SVikram.Hegde@Sun.COM } 38611600SVikram.Hegde@Sun.COM 38712683SJimmy.Vetayases@oracle.com static immu_t * 38812683SJimmy.Vetayases@oracle.com get_immu(dev_info_t *dip, uint16_t type, uchar_t ioapic_index) 38911600SVikram.Hegde@Sun.COM { 39011600SVikram.Hegde@Sun.COM immu_t *immu = NULL; 39111600SVikram.Hegde@Sun.COM 39212683SJimmy.Vetayases@oracle.com if (!DDI_INTR_IS_MSI_OR_MSIX(type)) { 39312683SJimmy.Vetayases@oracle.com immu = immu_dmar_ioapic_immu(ioapic_index); 39411600SVikram.Hegde@Sun.COM } else { 39512683SJimmy.Vetayases@oracle.com if (dip != NULL) 39612683SJimmy.Vetayases@oracle.com immu = immu_dmar_get_immu(dip); 39711600SVikram.Hegde@Sun.COM } 39811600SVikram.Hegde@Sun.COM 39912683SJimmy.Vetayases@oracle.com return (immu); 40011600SVikram.Hegde@Sun.COM } 40111600SVikram.Hegde@Sun.COM 40211600SVikram.Hegde@Sun.COM static int 40311600SVikram.Hegde@Sun.COM get_top_pcibridge(dev_info_t *dip, void *arg) 40411600SVikram.Hegde@Sun.COM { 40511600SVikram.Hegde@Sun.COM dev_info_t **topdipp = arg; 40611600SVikram.Hegde@Sun.COM immu_devi_t *immu_devi; 40711600SVikram.Hegde@Sun.COM 40811600SVikram.Hegde@Sun.COM mutex_enter(&(DEVI(dip)->devi_lock)); 40911600SVikram.Hegde@Sun.COM immu_devi = DEVI(dip)->devi_iommu; 41011600SVikram.Hegde@Sun.COM mutex_exit(&(DEVI(dip)->devi_lock)); 41111600SVikram.Hegde@Sun.COM 41211600SVikram.Hegde@Sun.COM if (immu_devi == NULL || immu_devi->imd_pcib_type == IMMU_PCIB_BAD || 41311600SVikram.Hegde@Sun.COM immu_devi->imd_pcib_type == IMMU_PCIB_ENDPOINT) { 41411600SVikram.Hegde@Sun.COM return (DDI_WALK_CONTINUE); 41511600SVikram.Hegde@Sun.COM } 41611600SVikram.Hegde@Sun.COM 41711600SVikram.Hegde@Sun.COM *topdipp = dip; 41811600SVikram.Hegde@Sun.COM 41911600SVikram.Hegde@Sun.COM return (DDI_WALK_CONTINUE); 42011600SVikram.Hegde@Sun.COM } 42111600SVikram.Hegde@Sun.COM 42211600SVikram.Hegde@Sun.COM static dev_info_t * 42311600SVikram.Hegde@Sun.COM intrmap_top_pcibridge(dev_info_t *rdip) 42411600SVikram.Hegde@Sun.COM { 42511600SVikram.Hegde@Sun.COM dev_info_t *top_pcibridge = NULL; 42611600SVikram.Hegde@Sun.COM 42711600SVikram.Hegde@Sun.COM if (immu_walk_ancestor(rdip, NULL, get_top_pcibridge, 42811600SVikram.Hegde@Sun.COM &top_pcibridge, NULL, 0) != DDI_SUCCESS) { 42911600SVikram.Hegde@Sun.COM return (NULL); 43011600SVikram.Hegde@Sun.COM } 43111600SVikram.Hegde@Sun.COM 43211600SVikram.Hegde@Sun.COM return (top_pcibridge); 43311600SVikram.Hegde@Sun.COM } 43411600SVikram.Hegde@Sun.COM 43511600SVikram.Hegde@Sun.COM /* function to get interrupt request source id */ 43612683SJimmy.Vetayases@oracle.com static uint32_t 43712683SJimmy.Vetayases@oracle.com get_sid(dev_info_t *dip, uint16_t type, uchar_t ioapic_index) 43811600SVikram.Hegde@Sun.COM { 43912683SJimmy.Vetayases@oracle.com dev_info_t *pdip; 44011600SVikram.Hegde@Sun.COM immu_devi_t *immu_devi; 44111600SVikram.Hegde@Sun.COM uint16_t sid; 44211600SVikram.Hegde@Sun.COM uchar_t svt, sq; 44311600SVikram.Hegde@Sun.COM 44411600SVikram.Hegde@Sun.COM if (!intrmap_enable_sid_verify) { 44512683SJimmy.Vetayases@oracle.com return (0); 44611600SVikram.Hegde@Sun.COM } 44711600SVikram.Hegde@Sun.COM 44812683SJimmy.Vetayases@oracle.com if (!DDI_INTR_IS_MSI_OR_MSIX(type)) { 44911600SVikram.Hegde@Sun.COM /* for interrupt through I/O APIC */ 45012683SJimmy.Vetayases@oracle.com sid = immu_dmar_ioapic_sid(ioapic_index); 45111600SVikram.Hegde@Sun.COM svt = SVT_ALL_VERIFY; 45211600SVikram.Hegde@Sun.COM sq = SQ_VERIFY_ALL; 45311600SVikram.Hegde@Sun.COM } else { 45411600SVikram.Hegde@Sun.COM /* MSI/MSI-X interrupt */ 45511600SVikram.Hegde@Sun.COM ASSERT(dip); 45611600SVikram.Hegde@Sun.COM pdip = intrmap_top_pcibridge(dip); 45711600SVikram.Hegde@Sun.COM ASSERT(pdip); 45811600SVikram.Hegde@Sun.COM immu_devi = DEVI(pdip)->devi_iommu; 45911600SVikram.Hegde@Sun.COM ASSERT(immu_devi); 46011600SVikram.Hegde@Sun.COM if (immu_devi->imd_pcib_type == IMMU_PCIB_PCIE_PCI) { 46111600SVikram.Hegde@Sun.COM /* device behind pcie to pci bridge */ 46211600SVikram.Hegde@Sun.COM sid = (immu_devi->imd_bus << 8) | immu_devi->imd_sec; 46311600SVikram.Hegde@Sun.COM svt = SVT_BUS_VERIFY; 46411600SVikram.Hegde@Sun.COM sq = SQ_VERIFY_ALL; 46511600SVikram.Hegde@Sun.COM } else { 46611600SVikram.Hegde@Sun.COM /* pcie device or device behind pci to pci bridge */ 46711600SVikram.Hegde@Sun.COM sid = (immu_devi->imd_bus << 8) | 46811600SVikram.Hegde@Sun.COM immu_devi->imd_devfunc; 46911600SVikram.Hegde@Sun.COM svt = SVT_ALL_VERIFY; 47011600SVikram.Hegde@Sun.COM sq = SQ_VERIFY_ALL; 47111600SVikram.Hegde@Sun.COM } 47211600SVikram.Hegde@Sun.COM } 47311600SVikram.Hegde@Sun.COM 47412683SJimmy.Vetayases@oracle.com return (sid | (svt << 18) | (sq << 16)); 47511600SVikram.Hegde@Sun.COM } 47611600SVikram.Hegde@Sun.COM 47711600SVikram.Hegde@Sun.COM static void 47811600SVikram.Hegde@Sun.COM intrmap_enable(immu_t *immu) 47911600SVikram.Hegde@Sun.COM { 48011600SVikram.Hegde@Sun.COM intrmap_t *intrmap; 48111600SVikram.Hegde@Sun.COM uint64_t irta_reg; 48211600SVikram.Hegde@Sun.COM 48311600SVikram.Hegde@Sun.COM intrmap = immu->immu_intrmap; 48411600SVikram.Hegde@Sun.COM 48511600SVikram.Hegde@Sun.COM irta_reg = intrmap->intrmap_paddr | intrmap_irta_s; 48611600SVikram.Hegde@Sun.COM if (intrmap_apic_mode == LOCAL_X2APIC) { 48711600SVikram.Hegde@Sun.COM irta_reg |= (0x1 << 11); 48811600SVikram.Hegde@Sun.COM } 48911600SVikram.Hegde@Sun.COM 49011600SVikram.Hegde@Sun.COM immu_regs_intrmap_enable(immu, irta_reg); 49111600SVikram.Hegde@Sun.COM } 49211600SVikram.Hegde@Sun.COM 49311600SVikram.Hegde@Sun.COM /* ####################################################################### */ 49411600SVikram.Hegde@Sun.COM 49511600SVikram.Hegde@Sun.COM /* 49611600SVikram.Hegde@Sun.COM * immu_intr_handler() 49711600SVikram.Hegde@Sun.COM * the fault event handler for a single immu unit 49811600SVikram.Hegde@Sun.COM */ 49911600SVikram.Hegde@Sun.COM int 50011600SVikram.Hegde@Sun.COM immu_intr_handler(immu_t *immu) 50111600SVikram.Hegde@Sun.COM { 50211600SVikram.Hegde@Sun.COM uint32_t status; 50311600SVikram.Hegde@Sun.COM int index, fault_reg_offset; 50411600SVikram.Hegde@Sun.COM int max_fault_index; 50511600SVikram.Hegde@Sun.COM boolean_t found_fault; 50611600SVikram.Hegde@Sun.COM dev_info_t *idip; 50711600SVikram.Hegde@Sun.COM 50811600SVikram.Hegde@Sun.COM mutex_enter(&(immu->immu_intr_lock)); 50911600SVikram.Hegde@Sun.COM mutex_enter(&(immu->immu_regs_lock)); 51011600SVikram.Hegde@Sun.COM 51111600SVikram.Hegde@Sun.COM /* read the fault status */ 51211600SVikram.Hegde@Sun.COM status = immu_regs_get32(immu, IMMU_REG_FAULT_STS); 51311600SVikram.Hegde@Sun.COM 51411600SVikram.Hegde@Sun.COM idip = immu->immu_dip; 51511600SVikram.Hegde@Sun.COM ASSERT(idip); 51611600SVikram.Hegde@Sun.COM 51711600SVikram.Hegde@Sun.COM /* check if we have a pending fault for this immu unit */ 51811600SVikram.Hegde@Sun.COM if ((status & IMMU_FAULT_STS_PPF) == 0) { 51911600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_regs_lock)); 52011600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_intr_lock)); 52111600SVikram.Hegde@Sun.COM return (DDI_INTR_UNCLAIMED); 52211600SVikram.Hegde@Sun.COM } 52311600SVikram.Hegde@Sun.COM 52411600SVikram.Hegde@Sun.COM /* 52511600SVikram.Hegde@Sun.COM * handle all primary pending faults 52611600SVikram.Hegde@Sun.COM */ 52711600SVikram.Hegde@Sun.COM index = IMMU_FAULT_GET_INDEX(status); 52811600SVikram.Hegde@Sun.COM max_fault_index = IMMU_CAP_GET_NFR(immu->immu_regs_cap) - 1; 52911600SVikram.Hegde@Sun.COM fault_reg_offset = IMMU_CAP_GET_FRO(immu->immu_regs_cap); 53011600SVikram.Hegde@Sun.COM 53111600SVikram.Hegde@Sun.COM found_fault = B_FALSE; 53211600SVikram.Hegde@Sun.COM _NOTE(CONSTCOND) 53311600SVikram.Hegde@Sun.COM while (1) { 53411600SVikram.Hegde@Sun.COM uint64_t val; 53511600SVikram.Hegde@Sun.COM uint8_t fault_reason; 53611600SVikram.Hegde@Sun.COM uint8_t fault_type; 53711600SVikram.Hegde@Sun.COM uint16_t sid; 53811600SVikram.Hegde@Sun.COM uint64_t pg_addr; 53911600SVikram.Hegde@Sun.COM uint64_t idx; 54011600SVikram.Hegde@Sun.COM 54111600SVikram.Hegde@Sun.COM /* read the higher 64bits */ 54211600SVikram.Hegde@Sun.COM val = immu_regs_get64(immu, fault_reg_offset + index * 16 + 8); 54311600SVikram.Hegde@Sun.COM 54411600SVikram.Hegde@Sun.COM /* check if this fault register has pending fault */ 54511600SVikram.Hegde@Sun.COM if (!IMMU_FRR_GET_F(val)) { 54611600SVikram.Hegde@Sun.COM break; 54711600SVikram.Hegde@Sun.COM } 54811600SVikram.Hegde@Sun.COM 54911600SVikram.Hegde@Sun.COM found_fault = B_TRUE; 55011600SVikram.Hegde@Sun.COM 55111600SVikram.Hegde@Sun.COM /* get the fault reason, fault type and sid */ 55211600SVikram.Hegde@Sun.COM fault_reason = IMMU_FRR_GET_FR(val); 55311600SVikram.Hegde@Sun.COM fault_type = IMMU_FRR_GET_FT(val); 55411600SVikram.Hegde@Sun.COM sid = IMMU_FRR_GET_SID(val); 55511600SVikram.Hegde@Sun.COM 55611600SVikram.Hegde@Sun.COM /* read the first 64bits */ 55711600SVikram.Hegde@Sun.COM val = immu_regs_get64(immu, fault_reg_offset + index * 16); 55811600SVikram.Hegde@Sun.COM pg_addr = val & IMMU_PAGEMASK; 55911600SVikram.Hegde@Sun.COM idx = val >> 48; 56011600SVikram.Hegde@Sun.COM 56111600SVikram.Hegde@Sun.COM /* clear the fault */ 56211600SVikram.Hegde@Sun.COM immu_regs_put32(immu, fault_reg_offset + index * 16 + 12, 56311600SVikram.Hegde@Sun.COM (((uint32_t)1) << 31)); 56411600SVikram.Hegde@Sun.COM 56511600SVikram.Hegde@Sun.COM /* report the fault info */ 56611600SVikram.Hegde@Sun.COM if (fault_reason < 0x20) { 56711600SVikram.Hegde@Sun.COM /* immu-remapping fault */ 56811600SVikram.Hegde@Sun.COM ddi_err(DER_WARN, idip, 56911600SVikram.Hegde@Sun.COM "generated a fault event when translating DMA %s\n" 57011600SVikram.Hegde@Sun.COM "\t on address 0x%" PRIx64 " for PCI(%d, %d, %d), " 57111600SVikram.Hegde@Sun.COM "the reason is:\n\t %s", 57211600SVikram.Hegde@Sun.COM fault_type ? "read" : "write", pg_addr, 57311600SVikram.Hegde@Sun.COM (sid >> 8) & 0xff, (sid >> 3) & 0x1f, sid & 0x7, 57411600SVikram.Hegde@Sun.COM immu_dvma_faults[MIN(fault_reason, 57511600SVikram.Hegde@Sun.COM DVMA_MAX_FAULTS)]); 57611600SVikram.Hegde@Sun.COM } else if (fault_reason < 0x27) { 57711600SVikram.Hegde@Sun.COM /* intr-remapping fault */ 57811600SVikram.Hegde@Sun.COM ddi_err(DER_WARN, idip, 57911600SVikram.Hegde@Sun.COM "generated a fault event when translating " 58011600SVikram.Hegde@Sun.COM "interrupt request\n" 58111600SVikram.Hegde@Sun.COM "\t on index 0x%" PRIx64 " for PCI(%d, %d, %d), " 58211600SVikram.Hegde@Sun.COM "the reason is:\n\t %s", 58311600SVikram.Hegde@Sun.COM idx, 58411600SVikram.Hegde@Sun.COM (sid >> 8) & 0xff, (sid >> 3) & 0x1f, sid & 0x7, 58511600SVikram.Hegde@Sun.COM immu_intrmap_faults[MIN((fault_reason - 0x20), 58611600SVikram.Hegde@Sun.COM INTRMAP_MAX_FAULTS)]); 58711600SVikram.Hegde@Sun.COM } else { 58811600SVikram.Hegde@Sun.COM ddi_err(DER_WARN, idip, "Unknown fault reason: 0x%x", 58911600SVikram.Hegde@Sun.COM fault_reason); 59011600SVikram.Hegde@Sun.COM } 59111600SVikram.Hegde@Sun.COM 59211600SVikram.Hegde@Sun.COM index++; 59311600SVikram.Hegde@Sun.COM if (index > max_fault_index) 59411600SVikram.Hegde@Sun.COM index = 0; 59511600SVikram.Hegde@Sun.COM } 59611600SVikram.Hegde@Sun.COM 59711600SVikram.Hegde@Sun.COM /* Clear the fault */ 59811600SVikram.Hegde@Sun.COM if (!found_fault) { 59911600SVikram.Hegde@Sun.COM ddi_err(DER_MODE, idip, 60011600SVikram.Hegde@Sun.COM "Fault register set but no fault present"); 60111600SVikram.Hegde@Sun.COM } 60211600SVikram.Hegde@Sun.COM immu_regs_put32(immu, IMMU_REG_FAULT_STS, 1); 60311600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_regs_lock)); 60411600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_intr_lock)); 60511600SVikram.Hegde@Sun.COM return (DDI_INTR_CLAIMED); 60611600SVikram.Hegde@Sun.COM } 60711600SVikram.Hegde@Sun.COM /* ######################################################################### */ 60811600SVikram.Hegde@Sun.COM 60911600SVikram.Hegde@Sun.COM /* 61011600SVikram.Hegde@Sun.COM * Interrupt remap entry points 61111600SVikram.Hegde@Sun.COM */ 61211600SVikram.Hegde@Sun.COM 61311600SVikram.Hegde@Sun.COM /* initialize interrupt remapping */ 61411600SVikram.Hegde@Sun.COM static int 61511600SVikram.Hegde@Sun.COM immu_intrmap_init(int apic_mode) 61611600SVikram.Hegde@Sun.COM { 61711600SVikram.Hegde@Sun.COM immu_t *immu; 61811600SVikram.Hegde@Sun.COM int error = DDI_FAILURE; 61911600SVikram.Hegde@Sun.COM 62011600SVikram.Hegde@Sun.COM if (immu_intrmap_enable == B_FALSE) { 62111600SVikram.Hegde@Sun.COM return (DDI_SUCCESS); 62211600SVikram.Hegde@Sun.COM } 62311600SVikram.Hegde@Sun.COM 62411600SVikram.Hegde@Sun.COM intrmap_apic_mode = apic_mode; 62511600SVikram.Hegde@Sun.COM 62611600SVikram.Hegde@Sun.COM immu = list_head(&immu_list); 62711600SVikram.Hegde@Sun.COM for (; immu; immu = list_next(&immu_list, immu)) { 62811600SVikram.Hegde@Sun.COM if ((immu->immu_intrmap_running == B_TRUE) && 62911600SVikram.Hegde@Sun.COM IMMU_ECAP_GET_IR(immu->immu_regs_excap)) { 63011600SVikram.Hegde@Sun.COM if (init_unit(immu) == DDI_SUCCESS) { 63111600SVikram.Hegde@Sun.COM error = DDI_SUCCESS; 63211600SVikram.Hegde@Sun.COM } 63311600SVikram.Hegde@Sun.COM } 63411600SVikram.Hegde@Sun.COM } 63511600SVikram.Hegde@Sun.COM 63611600SVikram.Hegde@Sun.COM /* 63711600SVikram.Hegde@Sun.COM * if all IOMMU units disable intr remapping, 63811600SVikram.Hegde@Sun.COM * return FAILURE 63911600SVikram.Hegde@Sun.COM */ 64011600SVikram.Hegde@Sun.COM return (error); 64111600SVikram.Hegde@Sun.COM } 64211600SVikram.Hegde@Sun.COM 64311600SVikram.Hegde@Sun.COM 64411600SVikram.Hegde@Sun.COM 64511600SVikram.Hegde@Sun.COM /* enable interrupt remapping */ 64611600SVikram.Hegde@Sun.COM static void 64711600SVikram.Hegde@Sun.COM immu_intrmap_switchon(int suppress_brdcst_eoi) 64811600SVikram.Hegde@Sun.COM { 64911600SVikram.Hegde@Sun.COM immu_t *immu; 65011600SVikram.Hegde@Sun.COM 65111600SVikram.Hegde@Sun.COM 65211600SVikram.Hegde@Sun.COM intrmap_suppress_brdcst_eoi = suppress_brdcst_eoi; 65311600SVikram.Hegde@Sun.COM 65411600SVikram.Hegde@Sun.COM immu = list_head(&immu_list); 65511600SVikram.Hegde@Sun.COM for (; immu; immu = list_next(&immu_list, immu)) { 65611600SVikram.Hegde@Sun.COM if (immu->immu_intrmap_setup == B_TRUE) { 65711600SVikram.Hegde@Sun.COM intrmap_enable(immu); 65811600SVikram.Hegde@Sun.COM } 65911600SVikram.Hegde@Sun.COM } 66011600SVikram.Hegde@Sun.COM } 66111600SVikram.Hegde@Sun.COM 66211600SVikram.Hegde@Sun.COM /* alloc remapping entry for the interrupt */ 66311600SVikram.Hegde@Sun.COM static void 66412683SJimmy.Vetayases@oracle.com immu_intrmap_alloc(void **intrmap_private_tbl, dev_info_t *dip, 66512683SJimmy.Vetayases@oracle.com uint16_t type, int count, uchar_t ioapic_index) 66611600SVikram.Hegde@Sun.COM { 66711600SVikram.Hegde@Sun.COM immu_t *immu; 66811600SVikram.Hegde@Sun.COM intrmap_t *intrmap; 66912683SJimmy.Vetayases@oracle.com uint32_t idx, i; 67011600SVikram.Hegde@Sun.COM uint32_t sid_svt_sq; 67112683SJimmy.Vetayases@oracle.com intrmap_private_t *intrmap_private; 67211600SVikram.Hegde@Sun.COM 67312683SJimmy.Vetayases@oracle.com if (intrmap_private_tbl[0] == INTRMAP_DISABLE || 67412683SJimmy.Vetayases@oracle.com intrmap_private_tbl[0] != NULL) { 67511600SVikram.Hegde@Sun.COM return; 67611600SVikram.Hegde@Sun.COM } 67711600SVikram.Hegde@Sun.COM 67812683SJimmy.Vetayases@oracle.com intrmap_private_tbl[0] = 67911600SVikram.Hegde@Sun.COM kmem_zalloc(sizeof (intrmap_private_t), KM_SLEEP); 68012683SJimmy.Vetayases@oracle.com intrmap_private = INTRMAP_PRIVATE(intrmap_private_tbl[0]); 68111600SVikram.Hegde@Sun.COM 68212683SJimmy.Vetayases@oracle.com immu = get_immu(dip, type, ioapic_index); 68312683SJimmy.Vetayases@oracle.com if ((immu != NULL) && (immu->immu_intrmap_running == B_TRUE)) { 68412683SJimmy.Vetayases@oracle.com intrmap_private->ir_immu = immu; 68512683SJimmy.Vetayases@oracle.com } else { 68611600SVikram.Hegde@Sun.COM goto intrmap_disable; 68711600SVikram.Hegde@Sun.COM } 68811600SVikram.Hegde@Sun.COM 68911600SVikram.Hegde@Sun.COM intrmap = immu->immu_intrmap; 69011600SVikram.Hegde@Sun.COM 69112683SJimmy.Vetayases@oracle.com if (count == 1) { 69211600SVikram.Hegde@Sun.COM idx = alloc_tbl_entry(intrmap); 69311600SVikram.Hegde@Sun.COM } else { 69412683SJimmy.Vetayases@oracle.com idx = alloc_tbl_multi_entries(intrmap, count); 69511600SVikram.Hegde@Sun.COM } 69611600SVikram.Hegde@Sun.COM 69711600SVikram.Hegde@Sun.COM if (idx == INTRMAP_IDX_FULL) { 69811600SVikram.Hegde@Sun.COM goto intrmap_disable; 69911600SVikram.Hegde@Sun.COM } 70011600SVikram.Hegde@Sun.COM 70112683SJimmy.Vetayases@oracle.com intrmap_private->ir_idx = idx; 70211600SVikram.Hegde@Sun.COM 70312683SJimmy.Vetayases@oracle.com sid_svt_sq = intrmap_private->ir_sid_svt_sq = 70412683SJimmy.Vetayases@oracle.com get_sid(dip, type, ioapic_index); 70511600SVikram.Hegde@Sun.COM 70612683SJimmy.Vetayases@oracle.com if (count == 1) { 70711600SVikram.Hegde@Sun.COM if (IMMU_CAP_GET_CM(immu->immu_regs_cap)) { 70811600SVikram.Hegde@Sun.COM immu_qinv_intr_one_cache(immu, idx); 70911600SVikram.Hegde@Sun.COM } else { 71011600SVikram.Hegde@Sun.COM immu_regs_wbf_flush(immu); 71111600SVikram.Hegde@Sun.COM } 71211600SVikram.Hegde@Sun.COM return; 71311600SVikram.Hegde@Sun.COM } 71411600SVikram.Hegde@Sun.COM 71512683SJimmy.Vetayases@oracle.com for (i = 1; i < count; i++) { 71612683SJimmy.Vetayases@oracle.com intrmap_private_tbl[i] = 71711600SVikram.Hegde@Sun.COM kmem_zalloc(sizeof (intrmap_private_t), KM_SLEEP); 71811600SVikram.Hegde@Sun.COM 71912683SJimmy.Vetayases@oracle.com INTRMAP_PRIVATE(intrmap_private_tbl[i])->ir_immu = immu; 72012683SJimmy.Vetayases@oracle.com INTRMAP_PRIVATE(intrmap_private_tbl[i])->ir_sid_svt_sq = 72112683SJimmy.Vetayases@oracle.com sid_svt_sq; 72212683SJimmy.Vetayases@oracle.com INTRMAP_PRIVATE(intrmap_private_tbl[i])->ir_idx = idx + i; 72311600SVikram.Hegde@Sun.COM } 72411600SVikram.Hegde@Sun.COM 72511600SVikram.Hegde@Sun.COM if (IMMU_CAP_GET_CM(immu->immu_regs_cap)) { 72612683SJimmy.Vetayases@oracle.com immu_qinv_intr_caches(immu, idx, count); 72711600SVikram.Hegde@Sun.COM } else { 72811600SVikram.Hegde@Sun.COM immu_regs_wbf_flush(immu); 72911600SVikram.Hegde@Sun.COM } 73011600SVikram.Hegde@Sun.COM 73111600SVikram.Hegde@Sun.COM return; 73211600SVikram.Hegde@Sun.COM 73311600SVikram.Hegde@Sun.COM intrmap_disable: 73412683SJimmy.Vetayases@oracle.com kmem_free(intrmap_private_tbl[0], sizeof (intrmap_private_t)); 73512683SJimmy.Vetayases@oracle.com intrmap_private_tbl[0] = INTRMAP_DISABLE; 73611600SVikram.Hegde@Sun.COM } 73711600SVikram.Hegde@Sun.COM 73811600SVikram.Hegde@Sun.COM 73911600SVikram.Hegde@Sun.COM /* remapping the interrupt */ 74011600SVikram.Hegde@Sun.COM static void 74112683SJimmy.Vetayases@oracle.com immu_intrmap_map(void *intrmap_private, void *intrmap_data, uint16_t type, 74212683SJimmy.Vetayases@oracle.com int count) 74311600SVikram.Hegde@Sun.COM { 74411600SVikram.Hegde@Sun.COM immu_t *immu; 74511600SVikram.Hegde@Sun.COM intrmap_t *intrmap; 74611600SVikram.Hegde@Sun.COM ioapic_rdt_t *irdt = (ioapic_rdt_t *)intrmap_data; 74711600SVikram.Hegde@Sun.COM msi_regs_t *mregs = (msi_regs_t *)intrmap_data; 74811600SVikram.Hegde@Sun.COM intrmap_rte_t irte; 74912683SJimmy.Vetayases@oracle.com uint_t idx, i; 75011600SVikram.Hegde@Sun.COM uint32_t dst, sid_svt_sq; 75111600SVikram.Hegde@Sun.COM uchar_t vector, dlm, tm, rh, dm; 75211600SVikram.Hegde@Sun.COM 75312683SJimmy.Vetayases@oracle.com if (intrmap_private == INTRMAP_DISABLE) 75411600SVikram.Hegde@Sun.COM return; 75511600SVikram.Hegde@Sun.COM 75612683SJimmy.Vetayases@oracle.com idx = INTRMAP_PRIVATE(intrmap_private)->ir_idx; 75712683SJimmy.Vetayases@oracle.com immu = INTRMAP_PRIVATE(intrmap_private)->ir_immu; 75812683SJimmy.Vetayases@oracle.com intrmap = immu->immu_intrmap; 75912683SJimmy.Vetayases@oracle.com sid_svt_sq = INTRMAP_PRIVATE(intrmap_private)->ir_sid_svt_sq; 76011600SVikram.Hegde@Sun.COM 76112683SJimmy.Vetayases@oracle.com if (!DDI_INTR_IS_MSI_OR_MSIX(type)) { 76211600SVikram.Hegde@Sun.COM dm = RDT_DM(irdt->ir_lo); 76311600SVikram.Hegde@Sun.COM rh = 0; 76411600SVikram.Hegde@Sun.COM tm = RDT_TM(irdt->ir_lo); 76511600SVikram.Hegde@Sun.COM dlm = RDT_DLM(irdt->ir_lo); 76611600SVikram.Hegde@Sun.COM dst = irdt->ir_hi; 76711600SVikram.Hegde@Sun.COM 76811600SVikram.Hegde@Sun.COM /* 76911600SVikram.Hegde@Sun.COM * Mark the IRTE's TM as Edge to suppress broadcast EOI. 77011600SVikram.Hegde@Sun.COM */ 77111600SVikram.Hegde@Sun.COM if (intrmap_suppress_brdcst_eoi) { 77211600SVikram.Hegde@Sun.COM tm = TRIGGER_MODE_EDGE; 77311600SVikram.Hegde@Sun.COM } 77412683SJimmy.Vetayases@oracle.com 77512683SJimmy.Vetayases@oracle.com vector = RDT_VECTOR(irdt->ir_lo); 77611600SVikram.Hegde@Sun.COM } else { 77711600SVikram.Hegde@Sun.COM dm = MSI_ADDR_DM_PHYSICAL; 77811600SVikram.Hegde@Sun.COM rh = MSI_ADDR_RH_FIXED; 77911600SVikram.Hegde@Sun.COM tm = TRIGGER_MODE_EDGE; 78011600SVikram.Hegde@Sun.COM dlm = 0; 78111600SVikram.Hegde@Sun.COM dst = mregs->mr_addr; 78212683SJimmy.Vetayases@oracle.com 78312683SJimmy.Vetayases@oracle.com vector = mregs->mr_data & 0xff; 78411600SVikram.Hegde@Sun.COM } 78511600SVikram.Hegde@Sun.COM 78611600SVikram.Hegde@Sun.COM if (intrmap_apic_mode == LOCAL_APIC) 78711600SVikram.Hegde@Sun.COM dst = (dst & 0xFF) << 8; 78811600SVikram.Hegde@Sun.COM 78912683SJimmy.Vetayases@oracle.com if (count == 1) { 79011600SVikram.Hegde@Sun.COM irte.lo = IRTE_LOW(dst, vector, dlm, tm, rh, dm, 0, 1); 79111600SVikram.Hegde@Sun.COM irte.hi = IRTE_HIGH(sid_svt_sq); 79211600SVikram.Hegde@Sun.COM 79311600SVikram.Hegde@Sun.COM /* set interrupt remapping table entry */ 79411600SVikram.Hegde@Sun.COM bcopy(&irte, intrmap->intrmap_vaddr + 79511600SVikram.Hegde@Sun.COM idx * INTRMAP_RTE_SIZE, 79611600SVikram.Hegde@Sun.COM INTRMAP_RTE_SIZE); 79711600SVikram.Hegde@Sun.COM 79811600SVikram.Hegde@Sun.COM immu_qinv_intr_one_cache(immu, idx); 79911600SVikram.Hegde@Sun.COM 80011600SVikram.Hegde@Sun.COM } else { 80112683SJimmy.Vetayases@oracle.com for (i = 0; i < count; i++) { 80211600SVikram.Hegde@Sun.COM irte.lo = IRTE_LOW(dst, vector, dlm, tm, rh, dm, 0, 1); 80311600SVikram.Hegde@Sun.COM irte.hi = IRTE_HIGH(sid_svt_sq); 80411600SVikram.Hegde@Sun.COM 80511600SVikram.Hegde@Sun.COM /* set interrupt remapping table entry */ 80611600SVikram.Hegde@Sun.COM bcopy(&irte, intrmap->intrmap_vaddr + 80711600SVikram.Hegde@Sun.COM idx * INTRMAP_RTE_SIZE, 80811600SVikram.Hegde@Sun.COM INTRMAP_RTE_SIZE); 80911600SVikram.Hegde@Sun.COM vector++; 81011600SVikram.Hegde@Sun.COM idx++; 81111600SVikram.Hegde@Sun.COM } 81211600SVikram.Hegde@Sun.COM 81312683SJimmy.Vetayases@oracle.com immu_qinv_intr_caches(immu, idx, count); 81411600SVikram.Hegde@Sun.COM } 81511600SVikram.Hegde@Sun.COM } 81611600SVikram.Hegde@Sun.COM 81711600SVikram.Hegde@Sun.COM /* free the remapping entry */ 81811600SVikram.Hegde@Sun.COM static void 81912683SJimmy.Vetayases@oracle.com immu_intrmap_free(void **intrmap_privatep) 82011600SVikram.Hegde@Sun.COM { 82111600SVikram.Hegde@Sun.COM immu_t *immu; 82211600SVikram.Hegde@Sun.COM intrmap_t *intrmap; 82311600SVikram.Hegde@Sun.COM uint32_t idx; 82411600SVikram.Hegde@Sun.COM 82512683SJimmy.Vetayases@oracle.com if (*intrmap_privatep == INTRMAP_DISABLE || *intrmap_privatep == NULL) { 82612683SJimmy.Vetayases@oracle.com *intrmap_privatep = NULL; 82711600SVikram.Hegde@Sun.COM return; 82811600SVikram.Hegde@Sun.COM } 82911600SVikram.Hegde@Sun.COM 83012683SJimmy.Vetayases@oracle.com immu = INTRMAP_PRIVATE(*intrmap_privatep)->ir_immu; 83111600SVikram.Hegde@Sun.COM intrmap = immu->immu_intrmap; 83212683SJimmy.Vetayases@oracle.com idx = INTRMAP_PRIVATE(*intrmap_privatep)->ir_idx; 83311600SVikram.Hegde@Sun.COM 83411600SVikram.Hegde@Sun.COM bzero(intrmap->intrmap_vaddr + idx * INTRMAP_RTE_SIZE, 83511600SVikram.Hegde@Sun.COM INTRMAP_RTE_SIZE); 83611600SVikram.Hegde@Sun.COM 83711600SVikram.Hegde@Sun.COM immu_qinv_intr_one_cache(immu, idx); 83811600SVikram.Hegde@Sun.COM 83911600SVikram.Hegde@Sun.COM mutex_enter(&intrmap->intrmap_lock); 84011600SVikram.Hegde@Sun.COM bitset_del(&intrmap->intrmap_map, idx); 84111600SVikram.Hegde@Sun.COM if (intrmap->intrmap_free == INTRMAP_IDX_FULL) { 84211600SVikram.Hegde@Sun.COM intrmap->intrmap_free = idx; 84311600SVikram.Hegde@Sun.COM } 84411600SVikram.Hegde@Sun.COM mutex_exit(&intrmap->intrmap_lock); 84511600SVikram.Hegde@Sun.COM 84612683SJimmy.Vetayases@oracle.com kmem_free(*intrmap_privatep, sizeof (intrmap_private_t)); 84712683SJimmy.Vetayases@oracle.com *intrmap_privatep = NULL; 84811600SVikram.Hegde@Sun.COM } 84911600SVikram.Hegde@Sun.COM 85011600SVikram.Hegde@Sun.COM /* record the ioapic rdt entry */ 85111600SVikram.Hegde@Sun.COM static void 85212683SJimmy.Vetayases@oracle.com immu_intrmap_rdt(void *intrmap_private, ioapic_rdt_t *irdt) 85311600SVikram.Hegde@Sun.COM { 85411600SVikram.Hegde@Sun.COM uint32_t rdt_entry, tm, pol, idx, vector; 85511600SVikram.Hegde@Sun.COM 85611600SVikram.Hegde@Sun.COM rdt_entry = irdt->ir_lo; 85711600SVikram.Hegde@Sun.COM 85812683SJimmy.Vetayases@oracle.com if (intrmap_private != INTRMAP_DISABLE && intrmap_private != NULL) { 85912683SJimmy.Vetayases@oracle.com idx = INTRMAP_PRIVATE(intrmap_private)->ir_idx; 86011600SVikram.Hegde@Sun.COM tm = RDT_TM(rdt_entry); 86111600SVikram.Hegde@Sun.COM pol = RDT_POL(rdt_entry); 86212683SJimmy.Vetayases@oracle.com vector = RDT_VECTOR(rdt_entry); 86311600SVikram.Hegde@Sun.COM irdt->ir_lo = (tm << INTRMAP_IOAPIC_TM_SHIFT) | 86411600SVikram.Hegde@Sun.COM (pol << INTRMAP_IOAPIC_POL_SHIFT) | 86511600SVikram.Hegde@Sun.COM ((idx >> 15) << INTRMAP_IOAPIC_IDX15_SHIFT) | 86611600SVikram.Hegde@Sun.COM vector; 86711600SVikram.Hegde@Sun.COM irdt->ir_hi = (idx << INTRMAP_IOAPIC_IDX_SHIFT) | 86811600SVikram.Hegde@Sun.COM (1 << INTRMAP_IOAPIC_FORMAT_SHIFT); 86911600SVikram.Hegde@Sun.COM } else { 87011600SVikram.Hegde@Sun.COM irdt->ir_hi <<= APIC_ID_BIT_OFFSET; 87111600SVikram.Hegde@Sun.COM } 87211600SVikram.Hegde@Sun.COM } 87311600SVikram.Hegde@Sun.COM 87411600SVikram.Hegde@Sun.COM /* record the msi interrupt structure */ 87511600SVikram.Hegde@Sun.COM /*ARGSUSED*/ 87611600SVikram.Hegde@Sun.COM static void 87712683SJimmy.Vetayases@oracle.com immu_intrmap_msi(void *intrmap_private, msi_regs_t *mregs) 87811600SVikram.Hegde@Sun.COM { 87911600SVikram.Hegde@Sun.COM uint_t idx; 88011600SVikram.Hegde@Sun.COM 88112683SJimmy.Vetayases@oracle.com if (intrmap_private != INTRMAP_DISABLE && intrmap_private != NULL) { 88212683SJimmy.Vetayases@oracle.com idx = INTRMAP_PRIVATE(intrmap_private)->ir_idx; 88311600SVikram.Hegde@Sun.COM 88411600SVikram.Hegde@Sun.COM mregs->mr_data = 0; 88511600SVikram.Hegde@Sun.COM mregs->mr_addr = MSI_ADDR_HDR | 88611600SVikram.Hegde@Sun.COM ((idx & 0x7fff) << INTRMAP_MSI_IDX_SHIFT) | 88711600SVikram.Hegde@Sun.COM (1 << INTRMAP_MSI_FORMAT_SHIFT) | 88811600SVikram.Hegde@Sun.COM (1 << INTRMAP_MSI_SHV_SHIFT) | 88911600SVikram.Hegde@Sun.COM ((idx >> 15) << INTRMAP_MSI_IDX15_SHIFT); 89011600SVikram.Hegde@Sun.COM } else { 89111600SVikram.Hegde@Sun.COM mregs->mr_addr = MSI_ADDR_HDR | 89211600SVikram.Hegde@Sun.COM (MSI_ADDR_RH_FIXED << MSI_ADDR_RH_SHIFT) | 89311600SVikram.Hegde@Sun.COM (MSI_ADDR_DM_PHYSICAL << MSI_ADDR_DM_SHIFT) | 89411600SVikram.Hegde@Sun.COM (mregs->mr_addr << MSI_ADDR_DEST_SHIFT); 89511600SVikram.Hegde@Sun.COM mregs->mr_data = (MSI_DATA_TM_EDGE << MSI_DATA_TM_SHIFT) | 89611600SVikram.Hegde@Sun.COM mregs->mr_data; 89711600SVikram.Hegde@Sun.COM } 89811600SVikram.Hegde@Sun.COM } 89911600SVikram.Hegde@Sun.COM 90011600SVikram.Hegde@Sun.COM /* ######################################################################### */ 90111600SVikram.Hegde@Sun.COM /* 90211600SVikram.Hegde@Sun.COM * Functions exported by immu_intr.c 90311600SVikram.Hegde@Sun.COM */ 90411600SVikram.Hegde@Sun.COM void 90511600SVikram.Hegde@Sun.COM immu_intrmap_setup(list_t *listp) 90611600SVikram.Hegde@Sun.COM { 90711600SVikram.Hegde@Sun.COM immu_t *immu; 90811600SVikram.Hegde@Sun.COM 90911600SVikram.Hegde@Sun.COM /* 91011600SVikram.Hegde@Sun.COM * Check if ACPI DMAR tables say that 91111600SVikram.Hegde@Sun.COM * interrupt remapping is supported 91211600SVikram.Hegde@Sun.COM */ 91311600SVikram.Hegde@Sun.COM if (immu_dmar_intrmap_supported() == B_FALSE) { 91411600SVikram.Hegde@Sun.COM return; 91511600SVikram.Hegde@Sun.COM } 91611600SVikram.Hegde@Sun.COM 91711600SVikram.Hegde@Sun.COM /* 91811600SVikram.Hegde@Sun.COM * Check if interrupt remapping is disabled. 91911600SVikram.Hegde@Sun.COM */ 92011600SVikram.Hegde@Sun.COM if (immu_intrmap_enable == B_FALSE) { 92111600SVikram.Hegde@Sun.COM return; 92211600SVikram.Hegde@Sun.COM } 92311600SVikram.Hegde@Sun.COM 92411600SVikram.Hegde@Sun.COM psm_vt_ops = &intrmap_ops; 92511600SVikram.Hegde@Sun.COM 92611600SVikram.Hegde@Sun.COM immu = list_head(listp); 92711600SVikram.Hegde@Sun.COM for (; immu; immu = list_next(listp, immu)) { 92811600SVikram.Hegde@Sun.COM mutex_init(&(immu->immu_intrmap_lock), NULL, 92911600SVikram.Hegde@Sun.COM MUTEX_DEFAULT, NULL); 93011600SVikram.Hegde@Sun.COM mutex_enter(&(immu->immu_intrmap_lock)); 93111600SVikram.Hegde@Sun.COM immu->immu_intrmap_setup = B_TRUE; 93211600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_intrmap_lock)); 93311600SVikram.Hegde@Sun.COM } 93411600SVikram.Hegde@Sun.COM } 93511600SVikram.Hegde@Sun.COM 93611600SVikram.Hegde@Sun.COM void 93711600SVikram.Hegde@Sun.COM immu_intrmap_startup(immu_t *immu) 93811600SVikram.Hegde@Sun.COM { 93911600SVikram.Hegde@Sun.COM /* do nothing */ 94011600SVikram.Hegde@Sun.COM mutex_enter(&(immu->immu_intrmap_lock)); 94111600SVikram.Hegde@Sun.COM if (immu->immu_intrmap_setup == B_TRUE) { 94211600SVikram.Hegde@Sun.COM immu->immu_intrmap_running = B_TRUE; 94311600SVikram.Hegde@Sun.COM } 94411600SVikram.Hegde@Sun.COM mutex_exit(&(immu->immu_intrmap_lock)); 94511600SVikram.Hegde@Sun.COM } 94611600SVikram.Hegde@Sun.COM 94711600SVikram.Hegde@Sun.COM /* 94811600SVikram.Hegde@Sun.COM * Register a Intel IOMMU unit (i.e. DMAR unit's) 94911600SVikram.Hegde@Sun.COM * interrupt handler 95011600SVikram.Hegde@Sun.COM */ 95111600SVikram.Hegde@Sun.COM void 95211600SVikram.Hegde@Sun.COM immu_intr_register(immu_t *immu) 95311600SVikram.Hegde@Sun.COM { 95411600SVikram.Hegde@Sun.COM int irq, vect; 95511600SVikram.Hegde@Sun.COM char intr_handler_name[IMMU_MAXNAMELEN]; 95611600SVikram.Hegde@Sun.COM uint32_t msi_data; 95711600SVikram.Hegde@Sun.COM uint32_t uaddr; 95811600SVikram.Hegde@Sun.COM uint32_t msi_addr; 95912683SJimmy.Vetayases@oracle.com uint32_t localapic_id = 0; 96012683SJimmy.Vetayases@oracle.com 96112683SJimmy.Vetayases@oracle.com if (psm_get_localapicid) 96212683SJimmy.Vetayases@oracle.com localapic_id = psm_get_localapicid(0); 96311600SVikram.Hegde@Sun.COM 96411600SVikram.Hegde@Sun.COM msi_addr = (MSI_ADDR_HDR | 96512683SJimmy.Vetayases@oracle.com ((localapic_id & 0xFF) << MSI_ADDR_DEST_SHIFT) | 96611600SVikram.Hegde@Sun.COM (MSI_ADDR_RH_FIXED << MSI_ADDR_RH_SHIFT) | 96711600SVikram.Hegde@Sun.COM (MSI_ADDR_DM_PHYSICAL << MSI_ADDR_DM_SHIFT)); 96811600SVikram.Hegde@Sun.COM 96911600SVikram.Hegde@Sun.COM if (intrmap_apic_mode == LOCAL_X2APIC) { 97012683SJimmy.Vetayases@oracle.com uaddr = localapic_id & 0xFFFFFF00; 97111600SVikram.Hegde@Sun.COM } else { 97211600SVikram.Hegde@Sun.COM uaddr = 0; 97311600SVikram.Hegde@Sun.COM } 97411600SVikram.Hegde@Sun.COM 97511600SVikram.Hegde@Sun.COM /* Dont need to hold immu_intr_lock since we are in boot */ 97612683SJimmy.Vetayases@oracle.com irq = vect = psm_get_ipivect(IMMU_INTR_IPL, -1); 97712683SJimmy.Vetayases@oracle.com if (psm_xlate_vector_by_irq != NULL) 97812683SJimmy.Vetayases@oracle.com vect = psm_xlate_vector_by_irq(irq); 97912683SJimmy.Vetayases@oracle.com 98011600SVikram.Hegde@Sun.COM msi_data = ((MSI_DATA_DELIVERY_FIXED << 98111600SVikram.Hegde@Sun.COM MSI_DATA_DELIVERY_SHIFT) | vect); 98211600SVikram.Hegde@Sun.COM 98311600SVikram.Hegde@Sun.COM (void) snprintf(intr_handler_name, sizeof (intr_handler_name), 98411600SVikram.Hegde@Sun.COM "%s-intr-handler", immu->immu_name); 98511600SVikram.Hegde@Sun.COM 98611600SVikram.Hegde@Sun.COM (void) add_avintr((void *)NULL, IMMU_INTR_IPL, 98711600SVikram.Hegde@Sun.COM (avfunc)(immu_intr_handler), intr_handler_name, irq, 98811600SVikram.Hegde@Sun.COM (caddr_t)immu, NULL, NULL, NULL); 98911600SVikram.Hegde@Sun.COM 99011600SVikram.Hegde@Sun.COM immu_regs_intr_enable(immu, msi_addr, msi_data, uaddr); 99111600SVikram.Hegde@Sun.COM 99211600SVikram.Hegde@Sun.COM (void) immu_intr_handler(immu); 99311600SVikram.Hegde@Sun.COM } 994