aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorJack Steiner <steiner@sgi.com>2011-09-20 16:55:04 -0400
committerThomas Gleixner <tglx@linutronix.de>2011-09-21 05:23:15 -0400
commit6a469e4665bc158599de55d64388861d0a9f10f4 (patch)
treeeb33002aa7dfbaae874406220c267284f0353604 /arch/x86
parent9d037a777695993ec7437e5f451647dea7919d4c (diff)
x86: uv2: Workaround for UV2 Hub bug (system global address format)
This is a workaround for a UV2 hub bug that affects the format of system global addresses. The GRU API for UV2 was inadvertently broken by a hardware change. The format of the physical address used for TLB dropins and for addresses used with instructions running in unmapped mode has changed. This change was not documented and became apparent only when diags failed running on system simulators. For UV1, TLB and GRU instruction physical addresses are identical to socket physical addresses (although high NASID bits must be OR'ed into the address). For UV2, socket physical addresses need to be converted. The NODE portion of the physical address needs to be shifted so that the low bit is in bit 39 or bit 40, depending on an MMR value. It is not yet clear if this bug will be fixed in a silicon respin. If it is fixed, the hub revision will be incremented & the workaround disabled. Signed-off-by: Jack Steiner <steiner@sgi.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: "H. Peter Anvin" <hpa@zytor.com> Cc: <stable@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/include/asm/uv/uv_bau.h1
-rw-r--r--arch/x86/include/asm/uv/uv_hub.h37
-rw-r--r--arch/x86/kernel/apic/x2apic_uv_x.c7
-rw-r--r--arch/x86/platform/uv/tlb_uv.c17
4 files changed, 46 insertions, 16 deletions
diff --git a/arch/x86/include/asm/uv/uv_bau.h b/arch/x86/include/asm/uv/uv_bau.h
index 37d369859c8..0c767a8e000 100644
--- a/arch/x86/include/asm/uv/uv_bau.h
+++ b/arch/x86/include/asm/uv/uv_bau.h
@@ -55,6 +55,7 @@
55#define UV_BAU_TUNABLES_DIR "sgi_uv" 55#define UV_BAU_TUNABLES_DIR "sgi_uv"
56#define UV_BAU_TUNABLES_FILE "bau_tunables" 56#define UV_BAU_TUNABLES_FILE "bau_tunables"
57#define WHITESPACE " \t\n" 57#define WHITESPACE " \t\n"
58#define uv_mmask ((1UL << uv_hub_info->m_val) - 1)
58#define uv_physnodeaddr(x) ((__pa((unsigned long)(x)) & uv_mmask)) 59#define uv_physnodeaddr(x) ((__pa((unsigned long)(x)) & uv_mmask))
59#define cpubit_isset(cpu, bau_local_cpumask) \ 60#define cpubit_isset(cpu, bau_local_cpumask) \
60 test_bit((cpu), (bau_local_cpumask).bits) 61 test_bit((cpu), (bau_local_cpumask).bits)
diff --git a/arch/x86/include/asm/uv/uv_hub.h b/arch/x86/include/asm/uv/uv_hub.h
index f26544a1521..54a13aaebc4 100644
--- a/arch/x86/include/asm/uv/uv_hub.h
+++ b/arch/x86/include/asm/uv/uv_hub.h
@@ -46,6 +46,13 @@
46 * PNODE - the low N bits of the GNODE. The PNODE is the most useful variant 46 * PNODE - the low N bits of the GNODE. The PNODE is the most useful variant
47 * of the nasid for socket usage. 47 * of the nasid for socket usage.
48 * 48 *
49 * GPA - (global physical address) a socket physical address converted
50 * so that it can be used by the GRU as a global address. Socket
51 * physical addresses 1) need additional NASID (node) bits added
52 * to the high end of the address, and 2) unaliased if the
53 * partition does not have a physical address 0. In addition, on
54 * UV2 rev 1, GPAs need the gnode left shifted to bits 39 or 40.
55 *
49 * 56 *
50 * NumaLink Global Physical Address Format: 57 * NumaLink Global Physical Address Format:
51 * +--------------------------------+---------------------+ 58 * +--------------------------------+---------------------+
@@ -141,6 +148,8 @@ struct uv_hub_info_s {
141 unsigned int gnode_extra; 148 unsigned int gnode_extra;
142 unsigned char hub_revision; 149 unsigned char hub_revision;
143 unsigned char apic_pnode_shift; 150 unsigned char apic_pnode_shift;
151 unsigned char m_shift;
152 unsigned char n_lshift;
144 unsigned long gnode_upper; 153 unsigned long gnode_upper;
145 unsigned long lowmem_remap_top; 154 unsigned long lowmem_remap_top;
146 unsigned long lowmem_remap_base; 155 unsigned long lowmem_remap_base;
@@ -177,6 +186,16 @@ static inline int is_uv2_hub(void)
177 return uv_hub_info->hub_revision >= UV2_HUB_REVISION_BASE; 186 return uv_hub_info->hub_revision >= UV2_HUB_REVISION_BASE;
178} 187}
179 188
189static inline int is_uv2_1_hub(void)
190{
191 return uv_hub_info->hub_revision == UV2_HUB_REVISION_BASE;
192}
193
194static inline int is_uv2_2_hub(void)
195{
196 return uv_hub_info->hub_revision == UV2_HUB_REVISION_BASE + 1;
197}
198
180union uvh_apicid { 199union uvh_apicid {
181 unsigned long v; 200 unsigned long v;
182 struct uvh_apicid_s { 201 struct uvh_apicid_s {
@@ -276,7 +295,10 @@ static inline unsigned long uv_soc_phys_ram_to_gpa(unsigned long paddr)
276{ 295{
277 if (paddr < uv_hub_info->lowmem_remap_top) 296 if (paddr < uv_hub_info->lowmem_remap_top)
278 paddr |= uv_hub_info->lowmem_remap_base; 297 paddr |= uv_hub_info->lowmem_remap_base;
279 return paddr | uv_hub_info->gnode_upper; 298 paddr |= uv_hub_info->gnode_upper;
299 paddr = ((paddr << uv_hub_info->m_shift) >> uv_hub_info->m_shift) |
300 ((paddr >> uv_hub_info->m_val) << uv_hub_info->n_lshift);
301 return paddr;
280} 302}
281 303
282 304
@@ -300,16 +322,19 @@ static inline unsigned long uv_gpa_to_soc_phys_ram(unsigned long gpa)
300 unsigned long remap_base = uv_hub_info->lowmem_remap_base; 322 unsigned long remap_base = uv_hub_info->lowmem_remap_base;
301 unsigned long remap_top = uv_hub_info->lowmem_remap_top; 323 unsigned long remap_top = uv_hub_info->lowmem_remap_top;
302 324
325 gpa = ((gpa << uv_hub_info->m_shift) >> uv_hub_info->m_shift) |
326 ((gpa >> uv_hub_info->n_lshift) << uv_hub_info->m_val);
327 gpa = gpa & uv_hub_info->gpa_mask;
303 if (paddr >= remap_base && paddr < remap_base + remap_top) 328 if (paddr >= remap_base && paddr < remap_base + remap_top)
304 paddr -= remap_base; 329 paddr -= remap_base;
305 return paddr; 330 return paddr;
306} 331}
307 332
308 333
309/* gnode -> pnode */ 334/* gpa -> pnode */
310static inline unsigned long uv_gpa_to_gnode(unsigned long gpa) 335static inline unsigned long uv_gpa_to_gnode(unsigned long gpa)
311{ 336{
312 return gpa >> uv_hub_info->m_val; 337 return gpa >> uv_hub_info->n_lshift;
313} 338}
314 339
315/* gpa -> pnode */ 340/* gpa -> pnode */
@@ -320,6 +345,12 @@ static inline int uv_gpa_to_pnode(unsigned long gpa)
320 return uv_gpa_to_gnode(gpa) & n_mask; 345 return uv_gpa_to_gnode(gpa) & n_mask;
321} 346}
322 347
348/* gpa -> node offset*/
349static inline unsigned long uv_gpa_to_offset(unsigned long gpa)
350{
351 return (gpa << uv_hub_info->m_shift) >> uv_hub_info->m_shift;
352}
353
323/* pnode, offset --> socket virtual */ 354/* pnode, offset --> socket virtual */
324static inline void *uv_pnode_offset_to_vaddr(int pnode, unsigned long offset) 355static inline void *uv_pnode_offset_to_vaddr(int pnode, unsigned long offset)
325{ 356{
diff --git a/arch/x86/kernel/apic/x2apic_uv_x.c b/arch/x86/kernel/apic/x2apic_uv_x.c
index 34b18594e72..cfeb978f49f 100644
--- a/arch/x86/kernel/apic/x2apic_uv_x.c
+++ b/arch/x86/kernel/apic/x2apic_uv_x.c
@@ -832,6 +832,10 @@ void __init uv_system_init(void)
832 uv_cpu_hub_info(cpu)->apic_pnode_shift = uvh_apicid.s.pnode_shift; 832 uv_cpu_hub_info(cpu)->apic_pnode_shift = uvh_apicid.s.pnode_shift;
833 uv_cpu_hub_info(cpu)->hub_revision = uv_hub_info->hub_revision; 833 uv_cpu_hub_info(cpu)->hub_revision = uv_hub_info->hub_revision;
834 834
835 uv_cpu_hub_info(cpu)->m_shift = 64 - m_val;
836 uv_cpu_hub_info(cpu)->n_lshift = is_uv2_1_hub() ?
837 (m_val == 40 ? 40 : 39) : m_val;
838
835 pnode = uv_apicid_to_pnode(apicid); 839 pnode = uv_apicid_to_pnode(apicid);
836 blade = boot_pnode_to_blade(pnode); 840 blade = boot_pnode_to_blade(pnode);
837 lcpu = uv_blade_info[blade].nr_possible_cpus; 841 lcpu = uv_blade_info[blade].nr_possible_cpus;
@@ -862,8 +866,7 @@ void __init uv_system_init(void)
862 if (uv_node_to_blade[nid] >= 0) 866 if (uv_node_to_blade[nid] >= 0)
863 continue; 867 continue;
864 paddr = node_start_pfn(nid) << PAGE_SHIFT; 868 paddr = node_start_pfn(nid) << PAGE_SHIFT;
865 paddr = uv_soc_phys_ram_to_gpa(paddr); 869 pnode = uv_gpa_to_pnode(uv_soc_phys_ram_to_gpa(paddr));
866 pnode = (paddr >> m_val) & pnode_mask;
867 blade = boot_pnode_to_blade(pnode); 870 blade = boot_pnode_to_blade(pnode);
868 uv_node_to_blade[nid] = blade; 871 uv_node_to_blade[nid] = blade;
869 } 872 }
diff --git a/arch/x86/platform/uv/tlb_uv.c b/arch/x86/platform/uv/tlb_uv.c
index db8b915f54b..5b552198f77 100644
--- a/arch/x86/platform/uv/tlb_uv.c
+++ b/arch/x86/platform/uv/tlb_uv.c
@@ -115,9 +115,6 @@ early_param("nobau", setup_nobau);
115 115
116/* base pnode in this partition */ 116/* base pnode in this partition */
117static int uv_base_pnode __read_mostly; 117static int uv_base_pnode __read_mostly;
118/* position of pnode (which is nasid>>1): */
119static int uv_nshift __read_mostly;
120static unsigned long uv_mmask __read_mostly;
121 118
122static DEFINE_PER_CPU(struct ptc_stats, ptcstats); 119static DEFINE_PER_CPU(struct ptc_stats, ptcstats);
123static DEFINE_PER_CPU(struct bau_control, bau_control); 120static DEFINE_PER_CPU(struct bau_control, bau_control);
@@ -1435,7 +1432,7 @@ static void activation_descriptor_init(int node, int pnode, int base_pnode)
1435{ 1432{
1436 int i; 1433 int i;
1437 int cpu; 1434 int cpu;
1438 unsigned long pa; 1435 unsigned long gpa;
1439 unsigned long m; 1436 unsigned long m;
1440 unsigned long n; 1437 unsigned long n;
1441 size_t dsize; 1438 size_t dsize;
@@ -1451,9 +1448,9 @@ static void activation_descriptor_init(int node, int pnode, int base_pnode)
1451 bau_desc = kmalloc_node(dsize, GFP_KERNEL, node); 1448 bau_desc = kmalloc_node(dsize, GFP_KERNEL, node);
1452 BUG_ON(!bau_desc); 1449 BUG_ON(!bau_desc);
1453 1450
1454 pa = uv_gpa(bau_desc); /* need the real nasid*/ 1451 gpa = uv_gpa(bau_desc);
1455 n = pa >> uv_nshift; 1452 n = uv_gpa_to_gnode(gpa);
1456 m = pa & uv_mmask; 1453 m = uv_gpa_to_offset(gpa);
1457 1454
1458 /* the 14-bit pnode */ 1455 /* the 14-bit pnode */
1459 write_mmr_descriptor_base(pnode, (n << UV_DESC_PSHIFT | m)); 1456 write_mmr_descriptor_base(pnode, (n << UV_DESC_PSHIFT | m));
@@ -1525,9 +1522,9 @@ static void pq_init(int node, int pnode)
1525 bcp->queue_last = pqp + (DEST_Q_SIZE - 1); 1522 bcp->queue_last = pqp + (DEST_Q_SIZE - 1);
1526 } 1523 }
1527 /* 1524 /*
1528 * need the pnode of where the memory was really allocated 1525 * need the gnode of where the memory was really allocated
1529 */ 1526 */
1530 pn = uv_gpa(pqp) >> uv_nshift; 1527 pn = uv_gpa_to_gnode(uv_gpa(pqp));
1531 first = uv_physnodeaddr(pqp); 1528 first = uv_physnodeaddr(pqp);
1532 pn_first = ((unsigned long)pn << UV_PAYLOADQ_PNODE_SHIFT) | first; 1529 pn_first = ((unsigned long)pn << UV_PAYLOADQ_PNODE_SHIFT) | first;
1533 last = uv_physnodeaddr(pqp + (DEST_Q_SIZE - 1)); 1530 last = uv_physnodeaddr(pqp + (DEST_Q_SIZE - 1));
@@ -1837,8 +1834,6 @@ static int __init uv_bau_init(void)
1837 zalloc_cpumask_var_node(mask, GFP_KERNEL, cpu_to_node(cur_cpu)); 1834 zalloc_cpumask_var_node(mask, GFP_KERNEL, cpu_to_node(cur_cpu));
1838 } 1835 }
1839 1836
1840 uv_nshift = uv_hub_info->m_val;
1841 uv_mmask = (1UL << uv_hub_info->m_val) - 1;
1842 nuvhubs = uv_num_possible_blades(); 1837 nuvhubs = uv_num_possible_blades();
1843 spin_lock_init(&disable_lock); 1838 spin_lock_init(&disable_lock);
1844 congested_cycles = usec_2_cycles(congested_respns_us); 1839 congested_cycles = usec_2_cycles(congested_respns_us);