diff options
| author | johnny <none@none> | 2006-07-10 13:38:31 -0700 |
|---|---|---|
| committer | johnny <none@none> | 2006-07-10 13:38:31 -0700 |
| commit | 0ccf9e790d232720597416743840df88825a9317 (patch) | |
| tree | 481502be55fc2323addc2def6cb6bc80d5ca5963 /usr/src | |
| parent | 58091fd8689db902780a10667e0e8118a9454b8f (diff) | |
| download | illumos-joyent-0ccf9e790d232720597416743840df88825a9317.tar.gz | |
6413021 x86: base MSI vector programmed to MSI data register does not conform to the PCI/MSI spec
Diffstat (limited to 'usr/src')
| -rw-r--r-- | usr/src/uts/i86pc/io/pcplusmp/apic.c | 3 | ||||
| -rw-r--r-- | usr/src/uts/i86pc/io/pcplusmp/apic.h | 12 | ||||
| -rw-r--r-- | usr/src/uts/i86pc/io/pcplusmp/apic_introp.c | 73 |
3 files changed, 60 insertions, 28 deletions
diff --git a/usr/src/uts/i86pc/io/pcplusmp/apic.c b/usr/src/uts/i86pc/io/pcplusmp/apic.c index 2052f1b085..d4531da93d 100644 --- a/usr/src/uts/i86pc/io/pcplusmp/apic.c +++ b/usr/src/uts/i86pc/io/pcplusmp/apic.c @@ -3977,8 +3977,7 @@ apic_allocate_vector(int ipl, int irq, int pri) highest -= APIC_HI_PRI_VECTS; for (i = lowest; i < highest; i++) { - if ((i == T_FASTTRAP) || (i == APIC_SPUR_INTR) || - (i == T_SYSCALLINT) || (i == T_DTRACE_RET)) + if (APIC_CHECK_RESERVE_VECTORS(i)) continue; if (apic_vector_to_irq[i] == APIC_RESV_IRQ) { apic_vector_to_irq[i] = (uchar_t)irq; diff --git a/usr/src/uts/i86pc/io/pcplusmp/apic.h b/usr/src/uts/i86pc/io/pcplusmp/apic.h index 7816040722..944f3e9523 100644 --- a/usr/src/uts/i86pc/io/pcplusmp/apic.h +++ b/usr/src/uts/i86pc/io/pcplusmp/apic.h @@ -2,9 +2,8 @@ * CDDL HEADER START * * The contents of this file are subject to the terms of the - * Common Development and Distribution License, Version 1.0 only - * (the "License"). You may not use this file except in compliance - * with the License. + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2005 Sun Microsystems, Inc. All rights reserved. + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -331,6 +330,11 @@ struct apic_io_intr { /* spurious interrupt vector */ #define APIC_SPUR_INTR 0xFF +/* special or reserve vectors */ +#define APIC_CHECK_RESERVE_VECTORS(v) \ + ((v == T_FASTTRAP) || (v == APIC_SPUR_INTR) || (v == T_SYSCALLINT) ||\ + (v == T_DTRACE_RET)) + /* cmos shutdown code for BIOS */ #define BIOS_SHUTDOWN 0x0a diff --git a/usr/src/uts/i86pc/io/pcplusmp/apic_introp.c b/usr/src/uts/i86pc/io/pcplusmp/apic_introp.c index acb837732f..b60771dcff 100644 --- a/usr/src/uts/i86pc/io/pcplusmp/apic_introp.c +++ b/usr/src/uts/i86pc/io/pcplusmp/apic_introp.c @@ -54,7 +54,7 @@ static void apic_clear_mask(apic_irq_t *); static void apic_set_mask(apic_irq_t *); static uchar_t apic_find_multi_vectors(int, int); int apic_navail_vector(dev_info_t *, int); -int apic_alloc_vectors(dev_info_t *, int, int, int, int); +int apic_alloc_vectors(dev_info_t *, int, int, int, int, int); void apic_free_vectors(dev_info_t *, int, int, int, int); int apic_intr_ops(dev_info_t *, ddi_intr_handle_impl_t *, psm_intr_op_t, int *); @@ -190,7 +190,7 @@ apic_navail_vector(dev_info_t *dip, int pri) count = 0; while ((apic_vector_to_irq[i] == APIC_RESV_IRQ) && (i < highest)) { - if ((i == T_FASTTRAP) || (i == APIC_SPUR_INTR)) + if (APIC_CHECK_RESERVE_VECTORS(i)) break; count++; i++; @@ -201,10 +201,16 @@ apic_navail_vector(dev_info_t *dip, int pri) return (navail); } +/* + * Finds "count" contiguous MSI vectors starting at the proper alignment + * at "pri". + * Caller needs to make sure that count has to be power of 2 and should not + * be < 1. + */ static uchar_t apic_find_multi_vectors(int pri, int count) { - int lowest, highest, i, navail, start; + int lowest, highest, i, navail, start, msibits; DDI_INTR_IMPLDBG((CE_CONT, "apic_find_mult: pri: %x, count: %x\n", pri, count)); @@ -213,13 +219,27 @@ apic_find_multi_vectors(int pri, int count) lowest = apic_ipltopri[pri - 1] + APIC_VECTOR_PER_IPL; navail = 0; + /* + * msibits is the no. of lower order message data bits for the + * allocated MSI vectors and is used to calculate the aligned + * starting vector + */ + msibits = count - 1; + /* It has to be contiguous */ for (i = lowest; i < highest; i++) { navail = 0; + + /* + * starting vector has to be aligned accordingly for + * multiple MSIs + */ + if (msibits) + i = (i + msibits) & ~msibits; start = i; while ((apic_vector_to_irq[i] == APIC_RESV_IRQ) && (i < highest)) { - if ((i == T_FASTTRAP) || (i == APIC_SPUR_INTR)) + if (APIC_CHECK_RESERVE_VECTORS(i)) break; navail++; if (navail >= count) @@ -230,7 +250,6 @@ apic_find_multi_vectors(int pri, int count) return (0); } - /* * It finds the apic_irq_t associates with the dip, ispec and type. */ @@ -369,23 +388,27 @@ apic_set_mask(apic_irq_t *irqp) * This function allocate "count" vector(s) for the given "dip/pri/type" */ int -apic_alloc_vectors(dev_info_t *dip, int inum, int count, int pri, int type) +apic_alloc_vectors(dev_info_t *dip, int inum, int count, int pri, int type, + int behavior) { int rcount, i; uchar_t start, irqno, cpu; - short idx; major_t major; apic_irq_t *irqptr; - /* for MSI/X only */ - if (!DDI_INTR_IS_MSI_OR_MSIX(type)) + /* only supports MSI at the moment, will add MSI-X support later */ + if (type != DDI_INTR_TYPE_MSI) return (0); DDI_INTR_IMPLDBG((CE_CONT, "apic_alloc_vectors: dip=0x%p type=%d " - "inum=0x%x pri=0x%x count=0x%x\n", - (void *)dip, type, inum, pri, count)); + "inum=0x%x pri=0x%x count=0x%x behavior=%d\n", + (void *)dip, type, inum, pri, count, behavior)); if (count > 1) { + if (behavior == DDI_INTR_ALLOC_STRICT && + (apic_multi_msi_enable == 0 || count > apic_multi_msi_max)) + return (0); + if (apic_multi_msi_enable == 0) count = 1; else if (count > apic_multi_msi_max) @@ -394,11 +417,19 @@ apic_alloc_vectors(dev_info_t *dip, int inum, int count, int pri, int type) if ((rcount = apic_navail_vector(dip, pri)) > count) rcount = count; + else if (rcount == 0 || (rcount < count && + behavior == DDI_INTR_ALLOC_STRICT)) + return (0); + + /* if not ISP2, then round it down */ + if (!ISP2(rcount)) + rcount = 1 << (highbit(rcount) - 1); mutex_enter(&airq_mutex); - for (start = 0; rcount > 0; rcount--) { - if ((start = apic_find_multi_vectors(pri, rcount)) != 0) + for (start = 0; rcount > 0; rcount >>= 1) { + if ((start = apic_find_multi_vectors(pri, rcount)) != 0 || + behavior == DDI_INTR_ALLOC_STRICT) break; } @@ -408,7 +439,6 @@ apic_alloc_vectors(dev_info_t *dip, int inum, int count, int pri, int type) return (0); } - idx = (short)((type == DDI_INTR_TYPE_MSI) ? MSI_INDEX : MSIX_INDEX); major = (dip != NULL) ? ddi_name_to_major(ddi_get_name(dip)) : 0; for (i = 0; i < rcount; i++) { if ((irqno = apic_allocate_irq(apic_first_avail_irq)) == @@ -435,7 +465,7 @@ apic_alloc_vectors(dev_info_t *dip, int inum, int count, int pri, int type) irqptr->airq_vector = start + i; irqptr->airq_origirq = (uchar_t)(inum + i); irqptr->airq_share_id = 0; - irqptr->airq_mps_intr_index = idx; + irqptr->airq_mps_intr_index = MSI_INDEX; irqptr->airq_dip = dip; irqptr->airq_major = major; if (i == 0) /* they all bound to the same cpu */ @@ -834,7 +864,8 @@ apic_intr_ops(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp, break; case PSM_INTR_OP_ALLOC_VECTORS: *result = apic_alloc_vectors(dip, hdlp->ih_inum, - hdlp->ih_scratch1, hdlp->ih_pri, hdlp->ih_type); + hdlp->ih_scratch1, hdlp->ih_pri, hdlp->ih_type, + (int)(uintptr_t)hdlp->ih_scratch2); break; case PSM_INTR_OP_FREE_VECTORS: apic_free_vectors(dip, hdlp->ih_inum, hdlp->ih_scratch1, @@ -890,14 +921,12 @@ apic_intr_ops(dev_info_t *dip, ddi_intr_handle_impl_t *hdlp, /* Now allocate the vectors */ count_vec = apic_alloc_vectors(dip, hdlp->ih_inum, - hdlp->ih_scratch1, new_priority, hdlp->ih_type); + hdlp->ih_scratch1, new_priority, hdlp->ih_type, + DDI_INTR_ALLOC_STRICT); - /* Did we get fewer vectors? */ - if (count_vec != hdlp->ih_scratch1) { - apic_free_vectors(dip, hdlp->ih_inum, count_vec, - new_priority, hdlp->ih_type); + /* Did we get the new vectors? */ + if (!count_vec) return (PSM_FAILURE); - } /* Finally, free the previously allocated vectors */ apic_free_vectors(dip, hdlp->ih_inum, count_vec, |
