Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 405422d8 authored by Mike Travis's avatar Mike Travis Committed by Ingo Molnar
Browse files

x86/platform/UV: Add UV4 addressing discovery function



UV4 requires early system wide addressing values.  This involves the use
of the CPUID instruction to obtain these values.  The current function
(detect_extended_topology()) in the kernel has been copied and streamlined,
with the limitation that only CPU's used by UV architectures are supported.

Tested-by: default avatarJohn Estabrook <estabrook@sgi.com>
Tested-by: default avatarGary Kroening <gfk@sgi.com>
Tested-by: default avatarNathan Zimmer <nzimmer@sgi.com>
Signed-off-by: default avatarMike Travis <travis@sgi.com>
Reviewed-by: default avatarDimitri Sivanich <sivanich@sgi.com>
Cc: Andrew Banman <abanman@sgi.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Len Brown <len.brown@intel.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Russ Anderson <rja@sgi.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20160429215405.155660884@asylum.americas.sgi.com


Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 906f3b20
Loading
Loading
Loading
Loading
+72 −13
Original line number Diff line number Diff line
@@ -48,6 +48,16 @@ static u64 gru_start_paddr, gru_end_paddr;
static u64 gru_dist_base, gru_first_node_paddr = -1LL, gru_last_node_paddr;
static u64 gru_dist_lmask, gru_dist_umask;
static union uvh_apicid uvh_apicid;

/* info derived from CPUID */
static struct {
	unsigned int apicid_shift;
	unsigned int apicid_mask;
	unsigned int socketid_shift;	/* aka pnode_shift for UV1/2/3 */
	unsigned int pnode_mask;
	unsigned int gpa_shift;
} uv_cpuid;

int uv_min_hub_revision_id;
EXPORT_SYMBOL_GPL(uv_min_hub_revision_id);
unsigned int uv_apicid_hibits;
@@ -127,18 +137,65 @@ static int __init early_get_pnodeid(void)
	}

	uv_hub_info->hub_revision = uv_min_hub_revision_id;
	pnode = (node_id.s.node_id >> 1) & ((1 << m_n_config.s.n_skt) - 1);
	uv_cpuid.pnode_mask = (1 << m_n_config.s.n_skt) - 1;
	pnode = (node_id.s.node_id >> 1) & uv_cpuid.pnode_mask;
	uv_cpuid.gpa_shift = 46;	/* default unless changed */

	pr_info("UV: rev:%d part#:%x nodeid:%04x n_skt:%d pnmsk:%x pn:%x\n",
		node_id.s.revision, node_id.s.part_number, node_id.s.node_id,
		m_n_config.s.n_skt, uv_cpuid.pnode_mask, pnode);
	return pnode;
}

static void __init early_get_apic_pnode_shift(void)
/* [copied from arch/x86/kernel/cpu/topology.c:detect_extended_topology()] */
#define SMT_LEVEL	0	/* leaf 0xb SMT level */
#define INVALID_TYPE	0	/* leaf 0xb sub-leaf types */
#define SMT_TYPE	1
#define CORE_TYPE	2
#define LEAFB_SUBTYPE(ecx)		(((ecx) >> 8) & 0xff)
#define BITS_SHIFT_NEXT_LEVEL(eax)	((eax) & 0x1f)

static void set_x2apic_bits(void)
{
	unsigned int eax, ebx, ecx, edx, sub_index;
	unsigned int sid_shift;

	cpuid(0, &eax, &ebx, &ecx, &edx);
	if (eax < 0xb) {
		pr_info("UV: CPU does not have CPUID.11\n");
		return;
	}
	cpuid_count(0xb, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
	if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE)) {
		pr_info("UV: CPUID.11 not implemented\n");
		return;
	}
	sid_shift = BITS_SHIFT_NEXT_LEVEL(eax);
	sub_index = 1;
	do {
		cpuid_count(0xb, sub_index, &eax, &ebx, &ecx, &edx);
		if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) {
			sid_shift = BITS_SHIFT_NEXT_LEVEL(eax);
			break;
		}
		sub_index++;
	} while (LEAFB_SUBTYPE(ecx) != INVALID_TYPE);
	uv_cpuid.apicid_shift = 0;
	uv_cpuid.apicid_mask = (~(-1 << sid_shift));
	uv_cpuid.socketid_shift = sid_shift;
}

static void __init early_get_apic_socketid_shift(void)
{
	if (is_uv2_hub() || is_uv3_hub())
		uvh_apicid.v = uv_early_read_mmr(UVH_APICID);
	if (!uvh_apicid.v)
		/*
		 * Old bios, use default value
		 */
		uvh_apicid.s.pnode_shift = UV_APIC_PNODE_SHIFT;

	set_x2apic_bits();

	pr_info("UV: apicid_shift:%d apicid_mask:0x%x\n",
		uv_cpuid.apicid_shift, uv_cpuid.apicid_mask);
	pr_info("UV: socketid_shift:%d pnode_mask:0x%x\n",
		uv_cpuid.socketid_shift, uv_cpuid.pnode_mask);
}

/*
@@ -186,7 +243,7 @@ static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
		goto badbios;

	pnodeid = early_get_pnodeid();
	early_get_apic_pnode_shift();
	early_get_apic_socketid_shift();
	x86_platform.is_untracked_pat_range =  uv_is_untracked_pat_range;
	x86_platform.nmi_init = uv_nmi_init;

@@ -917,11 +974,13 @@ void __init uv_init_hub_info(struct uv_hub_info_s *hub_info)
	hub_info->m_val = mn.m_val;
	hub_info->n_val = mn.n_val;
	hub_info->m_shift = mn.m_shift;
	hub_info->n_lshift = mn.n_lshift;
	hub_info->n_lshift = mn.n_lshift ? mn.n_lshift : 0;

	hub_info->hub_revision = uv_hub_info->hub_revision;
	hub_info->pnode_mask = (1 << mn.n_val) - 1;
	hub_info->gpa_mask = (1UL << (mn.m_val + mn.n_val)) - 1;
	hub_info->pnode_mask = uv_cpuid.pnode_mask;
	hub_info->gpa_mask = mn.m_val ?
		(1UL << (mn.m_val + mn.n_val)) - 1 :
		(1UL << uv_cpuid.gpa_shift) - 1;

	node_id.v = uv_read_local_mmr(UVH_NODE_ID);
	hub_info->gnode_extra =
@@ -937,7 +996,7 @@ void __init uv_init_hub_info(struct uv_hub_info_s *hub_info)
	get_lowmem_redirect(
		&hub_info->lowmem_remap_base, &hub_info->lowmem_remap_top);

	hub_info->apic_pnode_shift = uvh_apicid.s.pnode_shift;
	hub_info->apic_pnode_shift = uv_cpuid.socketid_shift;

	/* show system specific info */
	pr_info("UV: N:%d M:%d m_shift:%d n_lshift:%d\n",