diff options
| author | Dimitri Sivanich <sivanich@sgi.com> | 2010-11-16 17:23:52 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2010-11-18 04:41:25 -0500 |
| commit | 8191c9f69202d4dbc66063cb92059b8a58640d34 (patch) | |
| tree | 97efeba3b3224390bfac251ecb9e4a037c544453 | |
| parent | 9223081f54e3dc5045fe41a475165d9003c9a779 (diff) | |
x86: UV: Address interrupt/IO port operation conflict
This patch for SGI UV systems addresses a problem whereby
interrupt transactions being looped back from a local IOH,
through the hub to a local CPU can (erroneously) conflict with
IO port operations and other transactions.
To workaound this we set a high bit in the APIC IDs used for
interrupts. This bit appears to be ignored by the sockets, but
it avoids the conflict in the hub.
Signed-off-by: Dimitri Sivanich <sivanich@sgi.com>
LKML-Reference: <20101116222352.GA8155@sgi.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
___
arch/x86/include/asm/uv/uv_hub.h | 4 ++++
arch/x86/include/asm/uv/uv_mmrs.h | 19 ++++++++++++++++++-
arch/x86/kernel/apic/x2apic_uv_x.c | 25 +++++++++++++++++++++++--
arch/x86/platform/uv/tlb_uv.c | 2 +-
arch/x86/platform/uv/uv_time.c | 4 +++-
5 files changed, 49 insertions(+), 5 deletions(-)
| -rw-r--r-- | arch/x86/include/asm/uv/uv_hub.h | 4 | ||||
| -rw-r--r-- | arch/x86/include/asm/uv/uv_mmrs.h | 19 | ||||
| -rw-r--r-- | arch/x86/kernel/apic/x2apic_uv_x.c | 25 | ||||
| -rw-r--r-- | arch/x86/platform/uv/tlb_uv.c | 2 | ||||
| -rw-r--r-- | arch/x86/platform/uv/uv_time.c | 4 |
5 files changed, 49 insertions, 5 deletions
diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h index e969f691cbfd..a501741c2335 100644 --- a/arch/x86/include/asm/uv/uv_hub.h +++ b/arch/x86/include/asm/uv/uv_hub.h | |||
| @@ -199,6 +199,8 @@ union uvh_apicid { | |||
| 199 | #define UVH_APICID 0x002D0E00L | 199 | #define UVH_APICID 0x002D0E00L |
| 200 | #define UV_APIC_PNODE_SHIFT 6 | 200 | #define UV_APIC_PNODE_SHIFT 6 |
| 201 | 201 | ||
| 202 | #define UV_APICID_HIBIT_MASK 0xffff0000 | ||
| 203 | |||
| 202 | /* Local Bus from cpu's perspective */ | 204 | /* Local Bus from cpu's perspective */ |
| 203 | #define LOCAL_BUS_BASE 0x1c00000 | 205 | #define LOCAL_BUS_BASE 0x1c00000 |
| 204 | #define LOCAL_BUS_SIZE (4 * 1024 * 1024) | 206 | #define LOCAL_BUS_SIZE (4 * 1024 * 1024) |
| @@ -491,8 +493,10 @@ static inline void uv_set_cpu_scir_bits(int cpu, unsigned char value) | |||
| 491 | } | 493 | } |
| 492 | } | 494 | } |
| 493 | 495 | ||
| 496 | extern unsigned int uv_apicid_hibits; | ||
| 494 | static unsigned long uv_hub_ipi_value(int apicid, int vector, int mode) | 497 | static unsigned long uv_hub_ipi_value(int apicid, int vector, int mode) |
| 495 | { | 498 | { |
| 499 | apicid |= uv_apicid_hibits; | ||
| 496 | return (1UL << UVH_IPI_INT_SEND_SHFT) | | 500 | return (1UL << UVH_IPI_INT_SEND_SHFT) | |
| 497 | ((apicid) << UVH_IPI_INT_APIC_ID_SHFT) | | 501 | ((apicid) << UVH_IPI_INT_APIC_ID_SHFT) | |
| 498 | (mode << UVH_IPI_INT_DELIVERY_MODE_SHFT) | | 502 | (mode << UVH_IPI_INT_DELIVERY_MODE_SHFT) | |
diff --git a/arch/x86/include/asm/uv/uv_mmrs.h b/arch/x86/include/asm/uv/uv_mmrs.h index 6d90adf4428a..20cafeac7455 100644 --- a/arch/x86/include/asm/uv/uv_mmrs.h +++ b/arch/x86/include/asm/uv/uv_mmrs.h | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | * | 5 | * |
| 6 | * SGI UV MMR definitions | 6 | * SGI UV MMR definitions |
| 7 | * | 7 | * |
| 8 | * Copyright (C) 2007-2008 Silicon Graphics, Inc. All rights reserved. | 8 | * Copyright (C) 2007-2010 Silicon Graphics, Inc. All rights reserved. |
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #ifndef _ASM_X86_UV_UV_MMRS_H | 11 | #ifndef _ASM_X86_UV_UV_MMRS_H |
| @@ -754,6 +754,23 @@ union uvh_lb_bau_sb_descriptor_base_u { | |||
| 754 | }; | 754 | }; |
| 755 | 755 | ||
| 756 | /* ========================================================================= */ | 756 | /* ========================================================================= */ |
| 757 | /* UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK */ | ||
| 758 | /* ========================================================================= */ | ||
| 759 | #define UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK 0x320130UL | ||
| 760 | #define UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK_32 0x009f0 | ||
| 761 | |||
| 762 | #define UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK_BIT_ENABLES_SHFT 0 | ||
| 763 | #define UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK_BIT_ENABLES_MASK 0x00000000ffffffffUL | ||
| 764 | |||
| 765 | union uvh_lb_target_physical_apic_id_mask_u { | ||
| 766 | unsigned long v; | ||
| 767 | struct uvh_lb_target_physical_apic_id_mask_s { | ||
| 768 | unsigned long bit_enables : 32; /* RW */ | ||
| 769 | unsigned long rsvd_32_63 : 32; /* */ | ||
| 770 | } s; | ||
| 771 | }; | ||
| 772 | |||
| 773 | /* ========================================================================= */ | ||
| 757 | /* UVH_NODE_ID */ | 774 | /* UVH_NODE_ID */ |
| 758 | /* ========================================================================= */ | 775 | /* ========================================================================= */ |
| 759 | #define UVH_NODE_ID 0x0UL | 776 | #define UVH_NODE_ID 0x0UL |
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c index 194539aea175..c1c52c341f40 100644 --- a/arch/x86/kernel/apic/x2apic_uv_x.c +++ b/arch/x86/kernel/apic/x2apic_uv_x.c | |||
| @@ -44,6 +44,8 @@ static u64 gru_start_paddr, gru_end_paddr; | |||
| 44 | static union uvh_apicid uvh_apicid; | 44 | static union uvh_apicid uvh_apicid; |
| 45 | int uv_min_hub_revision_id; | 45 | int uv_min_hub_revision_id; |
| 46 | EXPORT_SYMBOL_GPL(uv_min_hub_revision_id); | 46 | EXPORT_SYMBOL_GPL(uv_min_hub_revision_id); |
| 47 | unsigned int uv_apicid_hibits; | ||
| 48 | EXPORT_SYMBOL_GPL(uv_apicid_hibits); | ||
| 47 | static DEFINE_SPINLOCK(uv_nmi_lock); | 49 | static DEFINE_SPINLOCK(uv_nmi_lock); |
| 48 | 50 | ||
| 49 | static inline bool is_GRU_range(u64 start, u64 end) | 51 | static inline bool is_GRU_range(u64 start, u64 end) |
| @@ -85,6 +87,23 @@ static void __init early_get_apic_pnode_shift(void) | |||
| 85 | uvh_apicid.s.pnode_shift = UV_APIC_PNODE_SHIFT; | 87 | uvh_apicid.s.pnode_shift = UV_APIC_PNODE_SHIFT; |
| 86 | } | 88 | } |
| 87 | 89 | ||
| 90 | /* | ||
| 91 | * Add an extra bit as dictated by bios to the destination apicid of | ||
| 92 | * interrupts potentially passing through the UV HUB. This prevents | ||
| 93 | * a deadlock between interrupts and IO port operations. | ||
| 94 | */ | ||
| 95 | static void __init uv_set_apicid_hibit(void) | ||
| 96 | { | ||
| 97 | union uvh_lb_target_physical_apic_id_mask_u apicid_mask; | ||
| 98 | unsigned long *mmr; | ||
| 99 | |||
| 100 | mmr = early_ioremap(UV_LOCAL_MMR_BASE | | ||
| 101 | UVH_LB_TARGET_PHYSICAL_APIC_ID_MASK, sizeof(*mmr)); | ||
| 102 | apicid_mask.v = *mmr; | ||
| 103 | early_iounmap(mmr, sizeof(*mmr)); | ||
| 104 | uv_apicid_hibits = apicid_mask.s.bit_enables & UV_APICID_HIBIT_MASK; | ||
| 105 | } | ||
| 106 | |||
| 88 | static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id) | 107 | static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id) |
| 89 | { | 108 | { |
| 90 | int nodeid; | 109 | int nodeid; |
| @@ -102,6 +121,7 @@ static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id) | |||
| 102 | __get_cpu_var(x2apic_extra_bits) = | 121 | __get_cpu_var(x2apic_extra_bits) = |
| 103 | nodeid << (uvh_apicid.s.pnode_shift - 1); | 122 | nodeid << (uvh_apicid.s.pnode_shift - 1); |
| 104 | uv_system_type = UV_NON_UNIQUE_APIC; | 123 | uv_system_type = UV_NON_UNIQUE_APIC; |
| 124 | uv_set_apicid_hibit(); | ||
| 105 | return 1; | 125 | return 1; |
| 106 | } | 126 | } |
| 107 | } | 127 | } |
| @@ -155,6 +175,7 @@ static int __cpuinit uv_wakeup_secondary(int phys_apicid, unsigned long start_ri | |||
| 155 | int pnode; | 175 | int pnode; |
| 156 | 176 | ||
| 157 | pnode = uv_apicid_to_pnode(phys_apicid); | 177 | pnode = uv_apicid_to_pnode(phys_apicid); |
| 178 | phys_apicid |= uv_apicid_hibits; | ||
| 158 | val = (1UL << UVH_IPI_INT_SEND_SHFT) | | 179 | val = (1UL << UVH_IPI_INT_SEND_SHFT) | |
| 159 | (phys_apicid << UVH_IPI_INT_APIC_ID_SHFT) | | 180 | (phys_apicid << UVH_IPI_INT_APIC_ID_SHFT) | |
| 160 | ((start_rip << UVH_IPI_INT_VECTOR_SHFT) >> 12) | | 181 | ((start_rip << UVH_IPI_INT_VECTOR_SHFT) >> 12) | |
| @@ -236,7 +257,7 @@ static unsigned int uv_cpu_mask_to_apicid(const struct cpumask *cpumask) | |||
| 236 | int cpu = cpumask_first(cpumask); | 257 | int cpu = cpumask_first(cpumask); |
| 237 | 258 | ||
| 238 | if ((unsigned)cpu < nr_cpu_ids) | 259 | if ((unsigned)cpu < nr_cpu_ids) |
| 239 | return per_cpu(x86_cpu_to_apicid, cpu); | 260 | return per_cpu(x86_cpu_to_apicid, cpu) | uv_apicid_hibits; |
| 240 | else | 261 | else |
| 241 | return BAD_APICID; | 262 | return BAD_APICID; |
| 242 | } | 263 | } |
| @@ -255,7 +276,7 @@ uv_cpu_mask_to_apicid_and(const struct cpumask *cpumask, | |||
| 255 | if (cpumask_test_cpu(cpu, cpu_online_mask)) | 276 | if (cpumask_test_cpu(cpu, cpu_online_mask)) |
| 256 | break; | 277 | break; |
| 257 | } | 278 | } |
| 258 | return per_cpu(x86_cpu_to_apicid, cpu); | 279 | return per_cpu(x86_cpu_to_apicid, cpu) | uv_apicid_hibits; |
| 259 | } | 280 | } |
| 260 | 281 | ||
| 261 | static unsigned int x2apic_get_apic_id(unsigned long x) | 282 | static unsigned int x2apic_get_apic_id(unsigned long x) |
diff --git a/arch/x86/platform/uv/tlb_uv.c b/arch/x86/platform/uv/tlb_uv.c index a318194002b5..ba9caa808a9c 100644 --- a/arch/x86/platform/uv/tlb_uv.c +++ b/arch/x86/platform/uv/tlb_uv.c | |||
| @@ -1455,7 +1455,7 @@ static void __init uv_init_uvhub(int uvhub, int vector) | |||
| 1455 | * the below initialization can't be in firmware because the | 1455 | * the below initialization can't be in firmware because the |
| 1456 | * messaging IRQ will be determined by the OS | 1456 | * messaging IRQ will be determined by the OS |
| 1457 | */ | 1457 | */ |
| 1458 | apicid = uvhub_to_first_apicid(uvhub); | 1458 | apicid = uvhub_to_first_apicid(uvhub) | uv_apicid_hibits; |
| 1459 | uv_write_global_mmr64(pnode, UVH_BAU_DATA_CONFIG, | 1459 | uv_write_global_mmr64(pnode, UVH_BAU_DATA_CONFIG, |
| 1460 | ((apicid << 32) | vector)); | 1460 | ((apicid << 32) | vector)); |
| 1461 | } | 1461 | } |
diff --git a/arch/x86/platform/uv/uv_time.c b/arch/x86/platform/uv/uv_time.c index 56e421bc379b..9daf5d1af9f1 100644 --- a/arch/x86/platform/uv/uv_time.c +++ b/arch/x86/platform/uv/uv_time.c | |||
| @@ -89,6 +89,7 @@ static void uv_rtc_send_IPI(int cpu) | |||
| 89 | 89 | ||
| 90 | apicid = cpu_physical_id(cpu); | 90 | apicid = cpu_physical_id(cpu); |
| 91 | pnode = uv_apicid_to_pnode(apicid); | 91 | pnode = uv_apicid_to_pnode(apicid); |
| 92 | apicid |= uv_apicid_hibits; | ||
| 92 | val = (1UL << UVH_IPI_INT_SEND_SHFT) | | 93 | val = (1UL << UVH_IPI_INT_SEND_SHFT) | |
| 93 | (apicid << UVH_IPI_INT_APIC_ID_SHFT) | | 94 | (apicid << UVH_IPI_INT_APIC_ID_SHFT) | |
| 94 | (X86_PLATFORM_IPI_VECTOR << UVH_IPI_INT_VECTOR_SHFT); | 95 | (X86_PLATFORM_IPI_VECTOR << UVH_IPI_INT_VECTOR_SHFT); |
| @@ -107,6 +108,7 @@ static int uv_intr_pending(int pnode) | |||
| 107 | static int uv_setup_intr(int cpu, u64 expires) | 108 | static int uv_setup_intr(int cpu, u64 expires) |
| 108 | { | 109 | { |
| 109 | u64 val; | 110 | u64 val; |
| 111 | unsigned long apicid = cpu_physical_id(cpu) | uv_apicid_hibits; | ||
| 110 | int pnode = uv_cpu_to_pnode(cpu); | 112 | int pnode = uv_cpu_to_pnode(cpu); |
| 111 | 113 | ||
| 112 | uv_write_global_mmr64(pnode, UVH_RTC1_INT_CONFIG, | 114 | uv_write_global_mmr64(pnode, UVH_RTC1_INT_CONFIG, |
| @@ -117,7 +119,7 @@ static int uv_setup_intr(int cpu, u64 expires) | |||
| 117 | UVH_EVENT_OCCURRED0_RTC1_MASK); | 119 | UVH_EVENT_OCCURRED0_RTC1_MASK); |
| 118 | 120 | ||
| 119 | val = (X86_PLATFORM_IPI_VECTOR << UVH_RTC1_INT_CONFIG_VECTOR_SHFT) | | 121 | val = (X86_PLATFORM_IPI_VECTOR << UVH_RTC1_INT_CONFIG_VECTOR_SHFT) | |
| 120 | ((u64)cpu_physical_id(cpu) << UVH_RTC1_INT_CONFIG_APIC_ID_SHFT); | 122 | ((u64)apicid << UVH_RTC1_INT_CONFIG_APIC_ID_SHFT); |
| 121 | 123 | ||
| 122 | /* Set configuration */ | 124 | /* Set configuration */ |
| 123 | uv_write_global_mmr64(pnode, UVH_RTC1_INT_CONFIG, val); | 125 | uv_write_global_mmr64(pnode, UVH_RTC1_INT_CONFIG, val); |
