Mercurial > illumos > illumos-gate
changeset 10345:160b63eaeb0a
6824013 Implement broadcast EOI suppression for Nehalem based processors having interrupt remapping support
author | Saurabh Misra <Saurabh.Mishra@Sun.COM> |
---|---|
date | Wed, 19 Aug 2009 14:53:50 -0700 |
parents | 67004039f55e |
children | 9f0b25e42dc5 |
files | usr/src/uts/i86pc/io/intel_iommu.c usr/src/uts/i86pc/io/mp_platform_common.c usr/src/uts/i86pc/io/pcplusmp/apic.c usr/src/uts/i86pc/io/pcplusmp/apic_regops.c usr/src/uts/i86pc/sys/apic.h |
diffstat | 5 files changed, 74 insertions(+), 39 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/i86pc/io/intel_iommu.c Wed Aug 19 12:13:19 2009 -0700 +++ b/usr/src/uts/i86pc/io/intel_iommu.c Wed Aug 19 14:53:50 2009 -0700 @@ -208,9 +208,15 @@ static uint_t intrr_irta_s = INTRR_MAX_IRTA_SIZE; /* - * whether disable interrupt remapping in LOCAL_APIC mode + * If true, arrange to suppress broadcast EOI by setting edge-triggered mode + * even for level-triggered interrupts in the interrupt-remapping engine. + * If false, broadcast EOI can still be suppressed if the CPU supports the + * APIC_SVR_SUPPRESS_BROADCAST_EOI bit. In both cases, the IOAPIC is still + * programmed with the correct trigger mode, and pcplusmp must send an EOI + * to the IOAPIC by writing to the IOAPIC's EOI register to make up for the + * missing broadcast EOI. */ -static int intrr_only_for_x2apic = 1; +static int intrr_suppress_brdcst_eoi = 0; /* * whether verify the source id of interrupt request @@ -282,7 +288,7 @@ static void intr_remap_get_sid(apic_irq_t *); static int intr_remap_init(int); -static void intr_remap_enable(void); +static void intr_remap_enable(int); static void intr_remap_alloc_entry(apic_irq_t *); static void intr_remap_map_entry(apic_irq_t *, void *); static void intr_remap_free_entry(apic_irq_t *); @@ -4265,13 +4271,6 @@ intrr_apic_mode = apic_mode; - if ((intrr_apic_mode != LOCAL_X2APIC) && intrr_only_for_x2apic) { - /* - * interrupt remapping is not a must in apic mode - */ - return (DDI_FAILURE); - } - for_each_in_list(&iommu_states, iommu) { if ((iommu->iu_enabled & QINV_ENABLE) && IOMMU_ECAP_GET_IR(iommu->iu_excapability)) { @@ -4294,10 +4293,12 @@ /* enable interrupt remapping */ static void -intr_remap_enable(void) +intr_remap_enable(int suppress_brdcst_eoi) { intel_iommu_state_t *iommu; + intrr_suppress_brdcst_eoi = suppress_brdcst_eoi; + for_each_in_list(&iommu_states, iommu) { if (iommu->iu_intr_remap_tbl) intr_remap_enable_unit(iommu); @@ -4508,10 +4509,17 @@ tm = RDT_TM(irdt->ir_lo); dlm = RDT_DLM(irdt->ir_lo); dst = irdt->ir_hi; + + /* + * Mark the IRTE's TM as Edge to suppress broadcast EOI. + */ + if (intrr_suppress_brdcst_eoi) { + tm = TRIGGER_MODE_EDGE; + } } else { dm = MSI_ADDR_DM_PHYSICAL; rh = MSI_ADDR_RH_FIXED; - tm = MSI_DATA_TM_EDGE; + tm = TRIGGER_MODE_EDGE; dlm = 0; dst = mregs->mr_addr; }
--- a/usr/src/uts/i86pc/io/mp_platform_common.c Wed Aug 19 12:13:19 2009 -0700 +++ b/usr/src/uts/i86pc/io/mp_platform_common.c Wed Aug 19 14:53:50 2009 -0700 @@ -645,6 +645,13 @@ } #endif + /* + * Check for directed-EOI capability in the local APIC. + */ + if (apic_directed_EOI_supported() == 1) { + apic_set_directed_EOI_handler(); + } + id = apic_reg_ops->apic_read(APIC_LID_REG); local_ids[0] = (uchar_t)(id >> 24); apic_nproc = index = 1;
--- a/usr/src/uts/i86pc/io/pcplusmp/apic.c Wed Aug 19 12:13:19 2009 -0700 +++ b/usr/src/uts/i86pc/io/pcplusmp/apic.c Wed Aug 19 14:53:50 2009 -0700 @@ -368,7 +368,7 @@ /* default apic ops without interrupt remapping */ static apic_intrr_ops_t apic_nointrr_ops = { (int (*)(int))return_instr, - (void (*)(void))return_instr, + (void (*)(int))return_instr, (void (*)(apic_irq_t *))return_instr, (void (*)(apic_irq_t *, void *))return_instr, (void (*)(apic_irq_t *))return_instr, @@ -601,13 +601,14 @@ AV_HIGH_ORDER >> cpun); } - if (apic_direct_EOI) { + if (apic_directed_EOI_supported()) { /* - * Set 12th bit in Spurious Interrupt Vector - * Register to support level triggered interrupt - * directed EOI. + * Setting the 12th bit in the Spurious Interrupt Vector + * Register suppresses broadcast EOIs generated by the local + * APIC. The suppression of broadcast EOIs happens only when + * interrupts are level-triggered. */ - svr |= (0x1 << APIC_SVR); + svr |= APIC_SVR_SUPPRESS_BROADCAST_EOI; } /* need to enable APIC before unmasking NMI */ @@ -753,7 +754,6 @@ { int i, j; uint_t isr; - uint32_t ver; /* * initialize interrupt remapping before apic @@ -796,16 +796,6 @@ "pcplusmp NMI handler", (caddr_t)NULL)) cmn_err(CE_WARN, "pcplusmp: Unable to add nmi handler"); - ver = apic_reg_ops->apic_read(APIC_VERS_REG); - /* - * In order to determine support for Directed EOI capability, - * we check for 24th bit in Local APIC Version Register. - */ - if (ver & (0x1 << APIC_DIRECTED_EOI)) { - apic_direct_EOI = 1; - apic_change_eoi(); - } - apic_init_intr(); /* enable apic mode if imcr present */ @@ -2596,11 +2586,24 @@ static void apic_intrr_init(int apic_mode) { + int suppress_brdcst_eoi = 0; + if (psm_vt_ops != NULL) { if (((apic_intrr_ops_t *)psm_vt_ops)->apic_intrr_init(apic_mode) == DDI_SUCCESS) { apic_vt_ops = psm_vt_ops; - apic_vt_ops->apic_intrr_enable(); + + /* + * We leverage the interrupt remapping engine to + * suppress broadcast EOI; thus we must send the + * directed EOI with the directed-EOI handler. + */ + if (apic_directed_EOI_supported() == 0) { + suppress_brdcst_eoi = 1; + apic_set_directed_EOI_handler(); + } + + apic_vt_ops->apic_intrr_enable(suppress_brdcst_eoi); } } }
--- a/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c Wed Aug 19 12:13:19 2009 -0700 +++ b/usr/src/uts/i86pc/io/pcplusmp/apic_regops.c Wed Aug 19 14:53:50 2009 -0700 @@ -91,8 +91,6 @@ /* * APIC register ops related data sturctures and functions. */ -int apic_direct_EOI = 0; /* Directed EOI Support */ - void apic_send_EOI(); void apic_send_directed_EOI(uint32_t irq); @@ -289,11 +287,23 @@ } void -apic_change_eoi() +apic_set_directed_EOI_handler() { apic_reg_ops->apic_send_eoi = apic_send_directed_EOI; } +int +apic_directed_EOI_supported() +{ + uint32_t ver; + + ver = apic_reg_ops->apic_read(APIC_VERS_REG); + if (ver & APIC_DIRECTED_EOI_BIT) + return (1); + + return (0); +} + /* * Change apic_reg_ops depending upon the apic_mode. */
--- a/usr/src/uts/i86pc/sys/apic.h Wed Aug 19 12:13:19 2009 -0700 +++ b/usr/src/uts/i86pc/sys/apic.h Wed Aug 19 14:53:50 2009 -0700 @@ -110,8 +110,8 @@ #define X2APIC_SELF_IPI 0xFC /* General x2APIC constants used at various places */ -#define APIC_SVR 12 -#define APIC_DIRECTED_EOI 24 +#define APIC_SVR_SUPPRESS_BROADCAST_EOI 0x1000 +#define APIC_DIRECTED_EOI_BIT 0x1000000 /* IRR register */ #define APIC_IRR_REG 0x80 @@ -428,6 +428,12 @@ #define MSI_ADDR_DM_SHIFT 2 /* + * TM is either edge or level. + */ +#define TRIGGER_MODE_EDGE 0x0 /* edge sensitive */ +#define TRIGGER_MODE_LEVEL 0x1 /* level sensitive */ + +/* * definitions for MSI Data */ #define MSI_DATA_DELIVERY_FIXED 0x0 /* Fixed delivery */ @@ -437,8 +443,8 @@ #define MSI_DATA_DELIVERY_INIT 0x5 #define MSI_DATA_DELIVERY_EXTINT 0x7 #define MSI_DATA_DELIVERY_SHIFT 8 -#define MSI_DATA_TM_EDGE 0x0 /* MSI is edge sensitive */ -#define MSI_DATA_TM_LEVEL 0x1 /* level sensitive */ +#define MSI_DATA_TM_EDGE TRIGGER_MODE_EDGE +#define MSI_DATA_TM_LEVEL TRIGGER_MODE_LEVEL #define MSI_DATA_TM_SHIFT 15 #define MSI_DATA_LEVEL_DEASSERT 0x0 #define MSI_DATA_LEVEL_ASSERT 0x1 /* Edge always assert */ @@ -552,7 +558,7 @@ */ typedef struct apic_intrr_ops { int (*apic_intrr_init)(int); - void (*apic_intrr_enable)(void); + void (*apic_intrr_enable)(int); void (*apic_intrr_alloc_entry)(apic_irq_t *); void (*apic_intrr_map_entry)(apic_irq_t *, void *); void (*apic_intrr_free_entry)(apic_irq_t *); @@ -850,10 +856,11 @@ extern uchar_t apic_ipls[]; extern apic_reg_ops_t *apic_reg_ops; extern int apic_mode; -extern int apic_direct_EOI; extern void x2apic_update_psm(); extern void apic_change_ops(); extern void apic_common_send_ipi(int, int); +extern void apic_set_directed_EOI_handler(); +extern int apic_directed_EOI_supported(); extern apic_intrr_ops_t *apic_vt_ops;