Skip to contentSkip to conversation

x86/UV: Set n_lshift based on GAM_GR_CONFIG MMR for UV3

PATCH In review Dimitri Sivanich 3 participants 6 messages Mar 20, 2014 – Apr 1, 2014

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 x86/UV: Set n_lshift based on GAM_GR_CONFIG MMR for UV3

Set the UV n_lshift value based on the GAM_GR_CONFIG MMR for UV3, making it independent of the socket m_val.

Remove unneeded macros.

---
 arch/x86/include/asm/uv/uv_hub.h   |   12 ---------
 arch/x86/include/asm/uv/uv_mmrs.h  |   42 ++++++++++++++++++++++++++++++++-
 arch/x86/kernel/apic/x2apic_uv_x.c |   15 +++++++++--
 3 files changed, 54 insertions(+), 15 deletions(-)
arch/x86/kernel/apic/x2apic_uv_x.c +12 -3
Index: linux/arch/x86/kernel/apic/x2apic_uv_x.c
===================================================================
@@ -5,7 +5,7 @@
  *
  * SGI UV APIC functions (note: not an Intel compatible APIC)
  *
- * Copyright (C) 2007-2013 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2007-2014 Silicon Graphics, Inc. All rights reserved.
  */
 #include <linux/cpumask.h>
 #include <linux/hardirq.h>
@@ -843,12 +843,14 @@ void uv_cpu_init(void)
 void __init uv_system_init(void)
 {
 	union uvh_rh_gam_config_mmr_u  m_n_config;
+	union uv3h_gr0_gam_gr_config_u m_gr_config;
 	union uvh_node_id_u node_id;
 	unsigned long gnode_upper, lowmem_redir_base, lowmem_redir_size;
 	int bytes, nid, cpu, lcpu, pnode, blade, i, j, m_val, n_val;
 	int gnode_extra, min_pnode = 999999, max_pnode = -1;
 	unsigned long mmr_base, present, paddr;
 	unsigned short pnode_mask;
+	unsigned char n_lshift;
 	char *hub = (is_uv1_hub() ? "UV1" :
 		    (is_uv2_hub() ? "UV2" :
 				    "UV3"));
@@ -859,6 +861,14 @@ void __init uv_system_init(void)
 	m_n_config.v = uv_read_local_mmr(UVH_RH_GAM_CONFIG_MMR );
 	m_val = m_n_config.s.m_skt;
 	n_val = m_n_config.s.n_skt;
+	if (is_uv1_hub())
+		n_lshift = m_val;
+	else if (is_uv2_hub())
+		n_lshift = m_val == 40 ? 40 : 39;
+	else {
+		m_gr_config.v = uv_read_local_mmr(UV3H_GR0_GAM_GR_CONFIG);
+		n_lshift = m_gr_config.s3.m_skt;
+	}
 	pnode_mask = (1 << n_val) - 1;
 	mmr_base =
 	    uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) &
@@ -935,8 +945,7 @@ void __init uv_system_init(void)
 		uv_cpu_hub_info(cpu)->hub_revision = uv_hub_info->hub_revision;
 
 		uv_cpu_hub_info(cpu)->m_shift = 64 - m_val;
-		uv_cpu_hub_info(cpu)->n_lshift = is_uv2_1_hub() ?
-				(m_val == 40 ? 40 : 39) : m_val;
+		uv_cpu_hub_info(cpu)->n_lshift = n_lshift;
 
 		pnode = uv_apicid_to_pnode(apicid);
 		blade = boot_pnode_to_blade(pnode);
arch/x86/include/asm/uv/uv_mmrs.h +41 -1

54 lines not on this page · raw message

arch/x86/include/asm/uv/uv_hub.h +1 -11
Index: linux/arch/x86/include/asm/uv/uv_hub.h
===================================================================
@@ -5,7 +5,7 @@
  *
  * SGI UV architectural definitions
  *
- * Copyright (C) 2007-2013 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2007-2014 Silicon Graphics, Inc. All rights reserved.
  */
 
 #ifndef _ASM_X86_UV_UV_HUB_H
@@ -204,16 +204,6 @@ static inline int is_uvx_hub(void)
 	return uv_hub_info->hub_revision >= UV2_HUB_REVISION_BASE;
 }
 
-static inline int is_uv2_1_hub(void)
-{
-	return uv_hub_info->hub_revision == UV2_HUB_REVISION_BASE;
-}
-
-static inline int is_uv2_2_hub(void)
-{
-	return uv_hub_info->hub_revision == UV2_HUB_REVISION_BASE + 1;
-}
-
 union uvh_apicid {
     unsigned long       v;
     struct uvh_apicid_s {
#1 lore raw
Quoted 11 lines · Dimitri Sivanich

Set the UV n_lshift value based on the GAM_GR_CONFIG MMR for UV3, making it independent of the socket m_val.

Remove unneeded macros.

---
 arch/x86/include/asm/uv/uv_hub.h   |   12 ---------
 arch/x86/include/asm/uv/uv_mmrs.h  |   42 ++++++++++++++++++++++++++++++++-
 arch/x86/kernel/apic/x2apic_uv_x.c |   15 +++++++++--
 3 files changed, 54 insertions(+), 15 deletions(-)

Please use the customary changelog style we use in the kernel:

" Current code does (A), this has a problem when (B).
We can improve this doing (C), because (D)."

(Of if it's a cleanup only with no functional effects then please state it so in the title and changelog.)

Thanks,

Ingo

#2 lore raw

PATCH 1/1 x86/UV: Set n_lshift based on GAM_GR_CONFIG MMR for UV3

Quoted 8 lines · Ingo Molnar

Please use the customary changelog style we use in the kernel:

" Current code does (A), this has a problem when (B).
We can improve this doing (C), because (D)."

(Of if it's a cleanup only with no functional effects then please state it so in the title and changelog.)

The value of n_lshift for UV is currently set based on the socket m_val.

For UV3, set the n_lshift value based on the GAM_GR_CONFIG MMR. This will allow bios to control the n_lshift value independent of the socket m_val. Then n_lshift can be assigned a fixed value across a multi-partition system, allowing for a fixed common global physical address format that is independent of socket m_val.

Cleanup unneeded macros.

---
 arch/x86/include/asm/uv/uv_hub.h   |   12 ---------
 arch/x86/include/asm/uv/uv_mmrs.h  |   42 ++++++++++++++++++++++++++++++++-
 arch/x86/kernel/apic/x2apic_uv_x.c |   15 +++++++++--
 3 files changed, 54 insertions(+), 15 deletions(-)
arch/x86/kernel/apic/x2apic_uv_x.c +12 -3
Index: linux/arch/x86/kernel/apic/x2apic_uv_x.c
===================================================================
@@ -5,7 +5,7 @@
  *
  * SGI UV APIC functions (note: not an Intel compatible APIC)
  *
- * Copyright (C) 2007-2013 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2007-2014 Silicon Graphics, Inc. All rights reserved.
  */
 #include <linux/cpumask.h>
 #include <linux/hardirq.h>
@@ -843,12 +843,14 @@ void uv_cpu_init(void)
 void __init uv_system_init(void)
 {
 	union uvh_rh_gam_config_mmr_u  m_n_config;
+	union uv3h_gr0_gam_gr_config_u m_gr_config;
 	union uvh_node_id_u node_id;
 	unsigned long gnode_upper, lowmem_redir_base, lowmem_redir_size;
 	int bytes, nid, cpu, lcpu, pnode, blade, i, j, m_val, n_val;
 	int gnode_extra, min_pnode = 999999, max_pnode = -1;
 	unsigned long mmr_base, present, paddr;
 	unsigned short pnode_mask;
+	unsigned char n_lshift;
 	char *hub = (is_uv1_hub() ? "UV1" :
 		    (is_uv2_hub() ? "UV2" :
 				    "UV3"));
@@ -859,6 +861,14 @@ void __init uv_system_init(void)
 	m_n_config.v = uv_read_local_mmr(UVH_RH_GAM_CONFIG_MMR );
 	m_val = m_n_config.s.m_skt;
 	n_val = m_n_config.s.n_skt;
+	if (is_uv1_hub())
+		n_lshift = m_val;
+	else if (is_uv2_hub())
+		n_lshift = m_val == 40 ? 40 : 39;
+	else {
+		m_gr_config.v = uv_read_local_mmr(UV3H_GR0_GAM_GR_CONFIG);
+		n_lshift = m_gr_config.s3.m_skt;
+	}
 	pnode_mask = (1 << n_val) - 1;
 	mmr_base =
 	    uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) &
@@ -935,8 +945,7 @@ void __init uv_system_init(void)
 		uv_cpu_hub_info(cpu)->hub_revision = uv_hub_info->hub_revision;
 
 		uv_cpu_hub_info(cpu)->m_shift = 64 - m_val;
-		uv_cpu_hub_info(cpu)->n_lshift = is_uv2_1_hub() ?
-				(m_val == 40 ? 40 : 39) : m_val;
+		uv_cpu_hub_info(cpu)->n_lshift = n_lshift;
 
 		pnode = uv_apicid_to_pnode(apicid);
 		blade = boot_pnode_to_blade(pnode);
arch/x86/include/asm/uv/uv_mmrs.h +41 -1

54 lines not on this page · raw message

arch/x86/include/asm/uv/uv_hub.h +1 -11
Index: linux/arch/x86/include/asm/uv/uv_hub.h
===================================================================
@@ -5,7 +5,7 @@
  *
  * SGI UV architectural definitions
  *
- * Copyright (C) 2007-2013 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2007-2014 Silicon Graphics, Inc. All rights reserved.
  */
 
 #ifndef _ASM_X86_UV_UV_HUB_H
@@ -204,16 +204,6 @@ static inline int is_uvx_hub(void)
 	return uv_hub_info->hub_revision >= UV2_HUB_REVISION_BASE;
 }
 
-static inline int is_uv2_1_hub(void)
-{
-	return uv_hub_info->hub_revision == UV2_HUB_REVISION_BASE;
-}
-
-static inline int is_uv2_2_hub(void)
-{
-	return uv_hub_info->hub_revision == UV2_HUB_REVISION_BASE + 1;
-}
-
 union uvh_apicid {
     unsigned long       v;
     struct uvh_apicid_s {
#3 lore raw
Quoted 57 lines · Dimitri Sivanich
Quoted 8 lines · Ingo Molnar

Please use the customary changelog style we use in the kernel:

" Current code does (A), this has a problem when (B).
We can improve this doing (C), because (D)."

(Of if it's a cleanup only with no functional effects then please state it so in the title and changelog.)

The value of n_lshift for UV is currently set based on the socket m_val.

For UV3, set the n_lshift value based on the GAM_GR_CONFIG MMR. This will allow bios to control the n_lshift value independent of the socket m_val. Then n_lshift can be assigned a fixed value across a multi-partition system, allowing for a fixed common global physical address format that is independent of socket m_val.

Cleanup unneeded macros.

---
 arch/x86/include/asm/uv/uv_hub.h   |   12 ---------
 arch/x86/include/asm/uv/uv_mmrs.h  |   42 ++++++++++++++++++++++++++++++++-
 arch/x86/kernel/apic/x2apic_uv_x.c |   15 +++++++++--
 3 files changed, 54 insertions(+), 15 deletions(-)

Index: linux/arch/x86/kernel/apic/x2apic_uv_x.c
===================================================================

arch/x86/kernel/apic/x2apic_uv_x.c +3 -1
@@ -5,7 +5,7 @@
  *
  * SGI UV APIC functions (note: not an Intel compatible APIC)
  *
- * Copyright (C) 2007-2013 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2007-2014 Silicon Graphics, Inc. All rights reserved.
  */
 #include <linux/cpumask.h>
 #include <linux/hardirq.h>
@@ -843,12 +843,14 @@ void uv_cpu_init(void)
 void __init uv_system_init(void)
 {
 	union uvh_rh_gam_config_mmr_u  m_n_config;
+	union uv3h_gr0_gam_gr_config_u m_gr_config;
 	union uvh_node_id_u node_id;
 	unsigned long gnode_upper, lowmem_redir_base, lowmem_redir_size;
 	int bytes, nid, cpu, lcpu, pnode, blade, i, j, m_val, n_val;
 	int gnode_extra, min_pnode = 999999, max_pnode = -1;
 	unsigned long mmr_base, present, paddr;
 	unsigned short pnode_mask;
+	unsigned char n_lshift;
 	char *hub = (is_uv1_hub() ? "UV1" :
 		    (is_uv2_hub() ? "UV2" :
 				    "UV3"));
@@ -859,6 +861,14 @@ void __init uv_system_init(void)
 	m_n_config.v = uv_read_local_mmr(UVH_RH_GAM_CONFIG_MMR );

arch/x86/kernel/apic/x2apic_uv_x.c void __init uv_system_init(void) · line 871

Quoted 10 lines
arch/x86/kernel/apic/x2apic_uv_x.c +8 -0
 	m_val = m_n_config.s.m_skt;
 	n_val = m_n_config.s.n_skt;
+	if (is_uv1_hub())
+		n_lshift = m_val;
+	else if (is_uv2_hub())
+		n_lshift = m_val == 40 ? 40 : 39;
+	else {
+		m_gr_config.v = uv_read_local_mmr(UV3H_GR0_GAM_GR_CONFIG);
+		n_lshift = m_gr_config.s3.m_skt;
+	}

This too should be in a helper inline, uv_system_init() is too large already.

The asymmetric curly braces are also non-standard.

Thanks,

Ingo

#4 lore raw
Quoted 23 lines · Ingo Molnar
Quoted 22 lines · Dimitri Sivanich
(quoted diff) +5 -0
@@ -843,12 +843,14 @@ void uv_cpu_init(void)
 void __init uv_system_init(void)
 {
 	union uvh_rh_gam_config_mmr_u  m_n_config;
+	union uv3h_gr0_gam_gr_config_u m_gr_config;
 	union uvh_node_id_u node_id;
 	unsigned long gnode_upper, lowmem_redir_base, lowmem_redir_size;
 	int bytes, nid, cpu, lcpu, pnode, blade, i, j, m_val, n_val;
 	int gnode_extra, min_pnode = 999999, max_pnode = -1;
 	unsigned long mmr_base, present, paddr;
 	unsigned short pnode_mask;
+	unsigned char n_lshift;
 	char *hub = (is_uv1_hub() ? "UV1" :
 		    (is_uv2_hub() ? "UV2" :
 				    "UV3"));
@@ -859,6 +861,14 @@ void __init uv_system_init(void)
 	m_n_config.v = uv_read_local_mmr(UVH_RH_GAM_CONFIG_MMR );
 	m_val = m_n_config.s.m_skt;
 	n_val = m_n_config.s.n_skt;
+	if (is_uv1_hub())
+		n_lshift = m_val;
+	else if (is_uv2_hub())
Quoted 8 lines

Review void __init uv_system_init(void) · line 871

Quoted 5 lines
(quoted diff) +5 -0
+		n_lshift = m_val == 40 ? 40 : 39;
+	else {
+		m_gr_config.v = uv_read_local_mmr(UV3H_GR0_GAM_GR_CONFIG);
+		n_lshift = m_gr_config.s3.m_skt;
+	}

This too should be in a helper inline, uv_system_init() is too large already.

Agreed.

Quoted 3 lines

The asymmetric curly braces are also non-standard.

OK. How does this look?

The value of n_lshift for UV is currently set based on the socket m_val.

For UV3, set the n_lshift value based on the GAM_GR_CONFIG MMR. This will allow bios to control the n_lshift value independent of the socket m_val. Then n_lshift can be assigned a fixed value across a multi-partition system, allowing for a fixed common global physical address format that is independent of socket m_val.

Cleanup unneeded macros.

---
 arch/x86/include/asm/uv/uv_hub.h   |   12 ---------
 arch/x86/include/asm/uv/uv_mmrs.h  |   42 ++++++++++++++++++++++++++++++++-
 arch/x86/kernel/apic/x2apic_uv_x.c |   26 ++++++++++++++++----
 3 files changed, 63 insertions(+), 17 deletions(-)
arch/x86/kernel/apic/x2apic_uv_x.c +21 -5
Index: linux/arch/x86/kernel/apic/x2apic_uv_x.c
===================================================================
@@ -5,7 +5,7 @@
  *
  * SGI UV APIC functions (note: not an Intel compatible APIC)
  *
- * Copyright (C) 2007-2013 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2007-2014 Silicon Graphics, Inc. All rights reserved.
  */
 #include <linux/cpumask.h>
 #include <linux/hardirq.h>
@@ -440,6 +440,20 @@ static __initdata struct redir_addr redi
 	{UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR, UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR},
 };
 
+static unsigned char get_n_lshift(int m_val)
+{
+	union uv3h_gr0_gam_gr_config_u m_gr_config;
+
+	if (is_uv1_hub())
+		return m_val;
+
+	if (is_uv2_hub())
+		return m_val == 40 ? 40 : 39;
+
+	m_gr_config.v = uv_read_local_mmr(UV3H_GR0_GAM_GR_CONFIG);
+	return m_gr_config.s3.m_skt;
+}
+
 static __init void get_lowmem_redirect(unsigned long *base, unsigned long *size)
 {
 	union uvh_rh_gam_alias210_overlay_config_2_mmr_u alias;
@@ -849,6 +863,7 @@ void __init uv_system_init(void)
 	int gnode_extra, min_pnode = 999999, max_pnode = -1;
 	unsigned long mmr_base, present, paddr;
 	unsigned short pnode_mask;
+	unsigned char n_lshift;
 	char *hub = (is_uv1_hub() ? "UV1" :
 		    (is_uv2_hub() ? "UV2" :
 				    "UV3"));
@@ -860,6 +875,7 @@ void __init uv_system_init(void)
 	m_val = m_n_config.s.m_skt;
 	n_val = m_n_config.s.n_skt;
 	pnode_mask = (1 << n_val) - 1;
+	n_lshift = get_n_lshift(m_val);
 	mmr_base =
 	    uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) &
 	    ~UV_MMR_ENABLE;
@@ -867,8 +883,9 @@ void __init uv_system_init(void)
 	node_id.v = uv_read_local_mmr(UVH_NODE_ID);
 	gnode_extra = (node_id.s.node_id & ~((1 << n_val) - 1)) >> 1;
 	gnode_upper = ((unsigned long)gnode_extra  << m_val);
-	pr_info("UV: N:%d M:%d pnode_mask:0x%x gnode_upper/extra:0x%lx/0x%x\n",
-			n_val, m_val, pnode_mask, gnode_upper, gnode_extra);
+	pr_info("UV: N:%d M:%d pnode_mask:0x%x gnode_upper/extra:0x%lx/0x%x n_lshift 0x%x\n",
+			n_val, m_val, pnode_mask, gnode_upper, gnode_extra,
+			n_lshift);
 
 	pr_info("UV: global MMR base 0x%lx\n", mmr_base);
 
@@ -935,8 +952,7 @@ void __init uv_system_init(void)
 		uv_cpu_hub_info(cpu)->hub_revision = uv_hub_info->hub_revision;
 
 		uv_cpu_hub_info(cpu)->m_shift = 64 - m_val;
-		uv_cpu_hub_info(cpu)->n_lshift = is_uv2_1_hub() ?
-				(m_val == 40 ? 40 : 39) : m_val;
+		uv_cpu_hub_info(cpu)->n_lshift = n_lshift;
 
 		pnode = uv_apicid_to_pnode(apicid);
 		blade = boot_pnode_to_blade(pnode);
arch/x86/include/asm/uv/uv_mmrs.h +41 -1

54 lines not on this page · raw message

arch/x86/include/asm/uv/uv_hub.h +1 -11
Index: linux/arch/x86/include/asm/uv/uv_hub.h
===================================================================
@@ -5,7 +5,7 @@
  *
  * SGI UV architectural definitions
  *
- * Copyright (C) 2007-2013 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2007-2014 Silicon Graphics, Inc. All rights reserved.
  */
 
 #ifndef _ASM_X86_UV_UV_HUB_H
@@ -204,16 +204,6 @@ static inline int is_uvx_hub(void)
 	return uv_hub_info->hub_revision >= UV2_HUB_REVISION_BASE;
 }
 
-static inline int is_uv2_1_hub(void)
-{
-	return uv_hub_info->hub_revision == UV2_HUB_REVISION_BASE;
-}
-
-static inline int is_uv2_2_hub(void)
-{
-	return uv_hub_info->hub_revision == UV2_HUB_REVISION_BASE + 1;
-}
-
 union uvh_apicid {
     unsigned long       v;
     struct uvh_apicid_s {
#5 lore raw
x86/UV: Set n_lshift based on GAM_GR_CONFIG MMR for UV3
Commit-ID:  5f40f7d93898a473eb222aa8064144c1d6835470
Gitweb:     http://git.kernel.org/tip/5f40f7d93898a473eb222aa8064144c1d6835470
Author:     Dimitri Sivanich <[email protected]>
AuthorDate: Mon, 31 Mar 2014 09:37:00 -0500
Committer:  Ingo Molnar <[email protected]>
CommitDate: Tue, 1 Apr 2014 12:10:44 +0200

x86/UV: Set n_lshift based on GAM_GR_CONFIG MMR for UV3

The value of n_lshift for UV is currently set based on the socket m_val.

For UV3, set the n_lshift value based on the GAM_GR_CONFIG MMR. This will allow bios to control the n_lshift value independent of the socket m_val. Then n_lshift can be assigned a fixed value across a multi-partition system, allowing for a fixed common global physical address format that is independent of socket m_val.

Cleanup unneeded macros.

---
 arch/x86/include/asm/uv/uv_hub.h   | 12 +----------
 arch/x86/include/asm/uv/uv_mmrs.h  | 42 +++++++++++++++++++++++++++++++++++++-
 arch/x86/kernel/apic/x2apic_uv_x.c | 26 ++++++++++++++++++-----
 3 files changed, 63 insertions(+), 17 deletions(-)
arch/x86/include/asm/uv/uv_hub.h +1 -11
index a30836c..c63e925 100644
@@ -5,7 +5,7 @@
  *
  * SGI UV architectural definitions
  *
- * Copyright (C) 2007-2013 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2007-2014 Silicon Graphics, Inc. All rights reserved.
  */
 
 #ifndef _ASM_X86_UV_UV_HUB_H
@@ -204,16 +204,6 @@ static inline int is_uvx_hub(void)
 	return uv_hub_info->hub_revision >= UV2_HUB_REVISION_BASE;
 }
 
-static inline int is_uv2_1_hub(void)
-{
-	return uv_hub_info->hub_revision == UV2_HUB_REVISION_BASE;
-}
-
-static inline int is_uv2_2_hub(void)
-{
-	return uv_hub_info->hub_revision == UV2_HUB_REVISION_BASE + 1;
-}
-
 union uvh_apicid {
     unsigned long       v;
     struct uvh_apicid_s {
arch/x86/include/asm/uv/uv_mmrs.h +41 -1

54 lines not on this page · raw message

arch/x86/kernel/apic/x2apic_uv_x.c +21 -5
index 7834389..293b41d 100644
@@ -5,7 +5,7 @@
  *
  * SGI UV APIC functions (note: not an Intel compatible APIC)
  *
- * Copyright (C) 2007-2013 Silicon Graphics, Inc. All rights reserved.
+ * Copyright (C) 2007-2014 Silicon Graphics, Inc. All rights reserved.
  */
 #include <linux/cpumask.h>
 #include <linux/hardirq.h>
@@ -440,6 +440,20 @@ static __initdata struct redir_addr redir_addrs[] = {
 	{UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR, UVH_RH_GAM_ALIAS210_OVERLAY_CONFIG_2_MMR},
 };
 
+static unsigned char get_n_lshift(int m_val)
+{
+	union uv3h_gr0_gam_gr_config_u m_gr_config;
+
+	if (is_uv1_hub())
+		return m_val;
+
+	if (is_uv2_hub())
+		return m_val == 40 ? 40 : 39;
+
+	m_gr_config.v = uv_read_local_mmr(UV3H_GR0_GAM_GR_CONFIG);
+	return m_gr_config.s3.m_skt;
+}
+
 static __init void get_lowmem_redirect(unsigned long *base, unsigned long *size)
 {
 	union uvh_rh_gam_alias210_overlay_config_2_mmr_u alias;
@@ -849,6 +863,7 @@ void __init uv_system_init(void)
 	int gnode_extra, min_pnode = 999999, max_pnode = -1;
 	unsigned long mmr_base, present, paddr;
 	unsigned short pnode_mask;
+	unsigned char n_lshift;
 	char *hub = (is_uv1_hub() ? "UV1" :
 		    (is_uv2_hub() ? "UV2" :
 				    "UV3"));
@@ -860,6 +875,7 @@ void __init uv_system_init(void)
 	m_val = m_n_config.s.m_skt;
 	n_val = m_n_config.s.n_skt;
 	pnode_mask = (1 << n_val) - 1;
+	n_lshift = get_n_lshift(m_val);
 	mmr_base =
 	    uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) &
 	    ~UV_MMR_ENABLE;
@@ -867,8 +883,9 @@ void __init uv_system_init(void)
 	node_id.v = uv_read_local_mmr(UVH_NODE_ID);
 	gnode_extra = (node_id.s.node_id & ~((1 << n_val) - 1)) >> 1;
 	gnode_upper = ((unsigned long)gnode_extra  << m_val);
-	pr_info("UV: N:%d M:%d pnode_mask:0x%x gnode_upper/extra:0x%lx/0x%x\n",
-			n_val, m_val, pnode_mask, gnode_upper, gnode_extra);
+	pr_info("UV: N:%d M:%d pnode_mask:0x%x gnode_upper/extra:0x%lx/0x%x n_lshift 0x%x\n",
+			n_val, m_val, pnode_mask, gnode_upper, gnode_extra,
+			n_lshift);
 
 	pr_info("UV: global MMR base 0x%lx\n", mmr_base);
 
@@ -935,8 +952,7 @@ void __init uv_system_init(void)
 		uv_cpu_hub_info(cpu)->hub_revision = uv_hub_info->hub_revision;
 
 		uv_cpu_hub_info(cpu)->m_shift = 64 - m_val;
-		uv_cpu_hub_info(cpu)->n_lshift = is_uv2_1_hub() ?
-				(m_val == 40 ? 40 : 39) : m_val;
+		uv_cpu_hub_info(cpu)->n_lshift = n_lshift;
 
 		pnode = uv_apicid_to_pnode(apicid);
 		blade = boot_pnode_to_blade(pnode);