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

Commit 1de329c1 authored by Mike Travis's avatar Mike Travis Committed by Ingo Molnar
Browse files

x86/platform/UV: Support UV4 socket address changes



With the UV4 system architecture addressing changes, BIOS now provides
this information via an EFI system table.  This is the initial decoding
of that system table.  It also collects the sizing information for
later allocation of dynamic conversion tables.

Tested-by: default avatarDimitri Sivanich <sivanich@sgi.com>
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.503022681@asylum.americas.sgi.com


Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent ef93bf80
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -147,15 +147,21 @@ struct uv_scir_s {
 */
struct uv_hub_info_s {
	unsigned long		global_mmr_base;
	unsigned long		global_mmr_shift;
	unsigned long		gpa_mask;
	unsigned int		gnode_extra;
	unsigned short		min_socket;
	unsigned short		min_pnode;
	unsigned char		hub_revision;
	unsigned char		apic_pnode_shift;
	unsigned char		gpa_shift;
	unsigned char		m_shift;
	unsigned char		n_lshift;
	unsigned int		gnode_extra;
	unsigned long		gnode_upper;
	unsigned long		lowmem_remap_top;
	unsigned long		lowmem_remap_base;
	unsigned long		global_gru_base;
	unsigned long		global_gru_shift;
	unsigned short		pnode;
	unsigned short		pnode_mask;
	unsigned short		coherency_domain_number;
@@ -362,7 +368,8 @@ union uvh_apicid {
#define UV_GLOBAL_GRU_MMR_BASE		0x4000000

#define UV_GLOBAL_MMR32_PNODE_SHIFT	15
#define UV_GLOBAL_MMR64_PNODE_SHIFT	26
#define _UV_GLOBAL_MMR64_PNODE_SHIFT	26
#define UV_GLOBAL_MMR64_PNODE_SHIFT	(uv_hub_info->global_mmr_shift)

#define UV_GLOBAL_MMR32_PNODE_BITS(p)	((p) << (UV_GLOBAL_MMR32_PNODE_SHIFT))

+120 −8
Original line number Diff line number Diff line
@@ -301,7 +301,13 @@ EXPORT_SYMBOL_GPL(uv_possible_blades);
unsigned long sn_rtc_cycles_per_second;
EXPORT_SYMBOL(sn_rtc_cycles_per_second);

/* the following values are used for the per node hub info struct */
static __initdata unsigned short *_node_to_pnode;
static __initdata unsigned short _min_socket, _max_socket;
static __initdata unsigned short _min_pnode, _max_pnode, _gr_table_len;
static __initdata struct uv_gam_range_entry *uv_gre_table;
static __initdata struct uv_gam_parameters *uv_gp_table;
#define	SOCK_EMPTY	((unsigned short)~0)

extern int uv_hub_info_version(void)
{
@@ -978,6 +984,7 @@ void __init uv_init_hub_info(struct uv_hub_info_s *hub_info)

	hub_info->hub_revision = uv_hub_info->hub_revision;
	hub_info->pnode_mask = uv_cpuid.pnode_mask;
	hub_info->min_pnode = _min_pnode;
	hub_info->gpa_mask = mn.m_val ?
		(1UL << (mn.m_val + mn.n_val)) - 1 :
		(1UL << uv_cpuid.gpa_shift) - 1;
@@ -989,9 +996,19 @@ void __init uv_init_hub_info(struct uv_hub_info_s *hub_info)
	hub_info->gnode_upper =
		((unsigned long)hub_info->gnode_extra << mn.m_val);

	if (uv_gp_table) {
		hub_info->global_mmr_base = uv_gp_table->mmr_base;
		hub_info->global_mmr_shift = uv_gp_table->mmr_shift;
		hub_info->global_gru_base = uv_gp_table->gru_base;
		hub_info->global_gru_shift = uv_gp_table->gru_shift;
		hub_info->gpa_shift = uv_gp_table->gpa_shift;
		hub_info->gpa_mask = (1UL << hub_info->gpa_shift) - 1;
	} else {
		hub_info->global_mmr_base =
			uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) &
					~UV_MMR_ENABLE;
		hub_info->global_mmr_shift = _UV_GLOBAL_MMR64_PNODE_SHIFT;
	}

	get_lowmem_redirect(
		&hub_info->lowmem_remap_base, &hub_info->lowmem_remap_top);
@@ -1003,15 +1020,109 @@ void __init uv_init_hub_info(struct uv_hub_info_s *hub_info)
		hub_info->n_val, hub_info->m_val,
		hub_info->m_shift, hub_info->n_lshift);

	pr_info("UV: pnode_mask:0x%x gpa_mask:0x%lx apic_pns:%d\n",
		hub_info->pnode_mask, hub_info->gpa_mask,
		hub_info->apic_pnode_shift);
	pr_info("UV: gpa_mask/shift:0x%lx/%d pnode_mask:0x%x apic_pns:%d\n",
		hub_info->gpa_mask, hub_info->gpa_shift,
		hub_info->pnode_mask, hub_info->apic_pnode_shift);

	pr_info("UV: mmr_base/shift:0x%lx/%ld gru_base/shift:0x%lx/%ld\n",
		hub_info->global_mmr_base, hub_info->global_mmr_shift,
		hub_info->global_gru_base, hub_info->global_gru_shift);

	pr_info("UV: gnode_upper:0x%lx gnode_extra:0x%x\n",
		hub_info->gnode_upper, hub_info->gnode_extra);
}

	pr_info("UV: global MMR base 0x%lx\n", hub_info->global_mmr_base);
static void __init decode_gam_params(unsigned long ptr)
{
	uv_gp_table = (struct uv_gam_parameters *)ptr;

	pr_info("UV: GAM Params...\n");
	pr_info("UV: mmr_base/shift:0x%llx/%d gru_base/shift:0x%llx/%d gpa_shift:%d\n",
		uv_gp_table->mmr_base, uv_gp_table->mmr_shift,
		uv_gp_table->gru_base, uv_gp_table->gru_shift,
		uv_gp_table->gpa_shift);
}

static void __init decode_gam_rng_tbl(unsigned long ptr)
{
	struct uv_gam_range_entry *gre = (struct uv_gam_range_entry *)ptr;
	unsigned long lgre = 0;
	int index = 0;
	int sock_min = 999999, pnode_min = 99999;
	int sock_max = -1, pnode_max = -1;

	uv_gre_table = gre;
	for (; gre->type != UV_GAM_RANGE_TYPE_UNUSED; gre++) {
		if (!index) {
			pr_info("UV: GAM Range Table...\n");
			pr_info("UV:  # %20s %14s %5s %4s %5s %3s %2s %3s\n",
				"Range", "", "Size", "Type", "NASID",
				"SID", "PN", "PXM");
		}
		pr_info(
		"UV: %2d: 0x%014lx-0x%014lx %5luG %3d   %04x  %02x %02x %3d\n",
			index++,
			(unsigned long)lgre << UV_GAM_RANGE_SHFT,
			(unsigned long)gre->limit << UV_GAM_RANGE_SHFT,
			((unsigned long)(gre->limit - lgre)) >>
				(30 - UV_GAM_RANGE_SHFT), /* 64M -> 1G */
			gre->type, gre->nasid, gre->sockid,
			gre->pnode, gre->pxm);

		lgre = gre->limit;
		if (sock_min > gre->sockid)
			sock_min = gre->sockid;
		if (sock_max < gre->sockid)
			sock_max = gre->sockid;
		if (pnode_min > gre->pnode)
			pnode_min = gre->pnode;
		if (pnode_max < gre->pnode)
			pnode_max = gre->pnode;
	}

	_min_socket = sock_min;
	_max_socket = sock_max;
	_min_pnode = pnode_min;
	_max_pnode = pnode_max;
	_gr_table_len = index;
	pr_info(
	"UV: GRT: %d entries, sockets(min:%x,max:%x) pnodes(min:%x,max:%x)\n",
		index, _min_socket, _max_socket, _min_pnode, _max_pnode);
}

static void __init decode_uv_systab(void)
{
	struct uv_systab *st;
	int i;

	st = uv_systab;
	if ((!st || st->revision < UV_SYSTAB_VERSION_UV4) && !is_uv4_hub())
		return;
	if (st->revision != UV_SYSTAB_VERSION_UV4_LATEST) {
		pr_crit(
		"UV: BIOS UVsystab version(%x) mismatch, expecting(%x)\n",
			st->revision, UV_SYSTAB_VERSION_UV4_LATEST);
		BUG();
	}

	for (i = 0; st->entry[i].type != UV_SYSTAB_TYPE_UNUSED; i++) {
		unsigned long ptr = st->entry[i].offset;

		if (!ptr)
			continue;

		ptr = ptr + (unsigned long)st;

		switch (st->entry[i].type) {
		case UV_SYSTAB_TYPE_GAM_PARAMS:
			decode_gam_params(ptr);
			break;

		case UV_SYSTAB_TYPE_GAM_RNG_TBL:
			decode_gam_rng_tbl(ptr);
			break;
		}
	}
}

/*
@@ -1080,6 +1191,8 @@ void __init uv_system_init(void)
	if (is_uv1_hub())
		map_low_mmrs();

	uv_bios_init();			/* get uv_systab for decoding */
	decode_uv_systab();
	uv_init_hub_info(&hub_info);
	uv_possible_blades = num_possible_nodes();
	if (!_node_to_pnode)
@@ -1091,7 +1204,6 @@ void __init uv_system_init(void)
			num_possible_nodes(),
			num_possible_cpus());

	uv_bios_init();
	uv_bios_get_sn_info(0, &uv_type, &sn_partition_id, &sn_coherency_id,
			    &sn_region_size, &system_serial_number);
	hub_info.coherency_domain_number = sn_coherency_id;