162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public 362306a36Sopenharmony_ci * License. See the file "COPYING" in the main directory of this archive 462306a36Sopenharmony_ci * for more details. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * SGI UV Core Functions 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Copyright (C) 2008 Silicon Graphics, Inc. All rights reserved. 962306a36Sopenharmony_ci */ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/acpi.h> 1262306a36Sopenharmony_ci#include <linux/efi.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/percpu.h> 1562306a36Sopenharmony_ci#include <asm/uv/uv.h> 1662306a36Sopenharmony_ci#include <asm/uv/uv_mmrs.h> 1762306a36Sopenharmony_ci#include <asm/uv/uv_hub.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cibool ia64_is_uv; 2062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ia64_is_uv); 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ciDEFINE_PER_CPU(struct uv_hub_info_s, __uv_hub_info); 2362306a36Sopenharmony_ciEXPORT_PER_CPU_SYMBOL_GPL(__uv_hub_info); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistruct redir_addr { 2662306a36Sopenharmony_ci unsigned long redirect; 2762306a36Sopenharmony_ci unsigned long alias; 2862306a36Sopenharmony_ci}; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define DEST_SHIFT UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_SHFT 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistatic __initdata struct redir_addr redir_addrs[] = { 3362306a36Sopenharmony_ci {UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR, UVH_SI_ALIAS0_OVERLAY_CONFIG}, 3462306a36Sopenharmony_ci {UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR, UVH_SI_ALIAS1_OVERLAY_CONFIG}, 3562306a36Sopenharmony_ci {UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR, UVH_SI_ALIAS2_OVERLAY_CONFIG}, 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic __init void get_lowmem_redirect(unsigned long *base, unsigned long *size) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci union uvh_si_alias0_overlay_config_u alias; 4162306a36Sopenharmony_ci union uvh_rh_gam_alias210_redirect_config_2_mmr_u redirect; 4262306a36Sopenharmony_ci int i; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(redir_addrs); i++) { 4562306a36Sopenharmony_ci alias.v = uv_read_local_mmr(redir_addrs[i].alias); 4662306a36Sopenharmony_ci if (alias.s.base == 0) { 4762306a36Sopenharmony_ci *size = (1UL << alias.s.m_alias); 4862306a36Sopenharmony_ci redirect.v = uv_read_local_mmr(redir_addrs[i].redirect); 4962306a36Sopenharmony_ci *base = (unsigned long)redirect.s.dest_base << DEST_SHIFT; 5062306a36Sopenharmony_ci return; 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci BUG(); 5462306a36Sopenharmony_ci} 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_civoid __init uv_probe_system_type(void) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci struct acpi_table_rsdp *rsdp; 5962306a36Sopenharmony_ci struct acpi_table_xsdt *xsdt; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci if (efi.acpi20 == EFI_INVALID_TABLE_ADDR) { 6262306a36Sopenharmony_ci pr_err("ACPI 2.0 RSDP not found.\n"); 6362306a36Sopenharmony_ci return; 6462306a36Sopenharmony_ci } 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci rsdp = (struct acpi_table_rsdp *)__va(efi.acpi20); 6762306a36Sopenharmony_ci if (strncmp(rsdp->signature, ACPI_SIG_RSDP, sizeof(ACPI_SIG_RSDP) - 1)) { 6862306a36Sopenharmony_ci pr_err("ACPI 2.0 RSDP signature incorrect.\n"); 6962306a36Sopenharmony_ci return; 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci xsdt = (struct acpi_table_xsdt *)__va(rsdp->xsdt_physical_address); 7362306a36Sopenharmony_ci if (strncmp(xsdt->header.signature, ACPI_SIG_XSDT, 7462306a36Sopenharmony_ci sizeof(ACPI_SIG_XSDT) - 1)) { 7562306a36Sopenharmony_ci pr_err("ACPI 2.0 XSDT signature incorrect.\n"); 7662306a36Sopenharmony_ci return; 7762306a36Sopenharmony_ci } 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci if (!strcmp(xsdt->header.oem_id, "SGI") && 8062306a36Sopenharmony_ci !strcmp(xsdt->header.oem_table_id + 4, "UV")) 8162306a36Sopenharmony_ci ia64_is_uv = true; 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_civoid __init uv_setup(char **cmdline_p) 8562306a36Sopenharmony_ci{ 8662306a36Sopenharmony_ci union uvh_si_addr_map_config_u m_n_config; 8762306a36Sopenharmony_ci union uvh_node_id_u node_id; 8862306a36Sopenharmony_ci unsigned long gnode_upper; 8962306a36Sopenharmony_ci int nid, cpu, m_val, n_val; 9062306a36Sopenharmony_ci unsigned long mmr_base, lowmem_redir_base, lowmem_redir_size; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci get_lowmem_redirect(&lowmem_redir_base, &lowmem_redir_size); 9362306a36Sopenharmony_ci node_id.v = uv_read_local_mmr(UVH_NODE_ID); 9462306a36Sopenharmony_ci m_n_config.v = uv_read_local_mmr(UVH_SI_ADDR_MAP_CONFIG); 9562306a36Sopenharmony_ci mmr_base = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) & 9662306a36Sopenharmony_ci ~UV_MMR_ENABLE; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci m_val = m_n_config.s.m_skt; 9962306a36Sopenharmony_ci n_val = m_n_config.s.n_skt; 10062306a36Sopenharmony_ci printk(KERN_DEBUG "UV: global MMR base 0x%lx\n", mmr_base); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci gnode_upper = (((unsigned long)node_id.s.node_id) & 10362306a36Sopenharmony_ci ~((1 << n_val) - 1)) << m_val; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci for_each_present_cpu(cpu) { 10662306a36Sopenharmony_ci nid = cpu_to_node(cpu); 10762306a36Sopenharmony_ci uv_cpu_hub_info(cpu)->lowmem_remap_base = lowmem_redir_base; 10862306a36Sopenharmony_ci uv_cpu_hub_info(cpu)->lowmem_remap_top = 10962306a36Sopenharmony_ci lowmem_redir_base + lowmem_redir_size; 11062306a36Sopenharmony_ci uv_cpu_hub_info(cpu)->m_val = m_val; 11162306a36Sopenharmony_ci uv_cpu_hub_info(cpu)->n_val = n_val; 11262306a36Sopenharmony_ci uv_cpu_hub_info(cpu)->pnode_mask = (1 << n_val) -1; 11362306a36Sopenharmony_ci uv_cpu_hub_info(cpu)->gpa_mask = (1 << (m_val + n_val)) - 1; 11462306a36Sopenharmony_ci uv_cpu_hub_info(cpu)->gnode_upper = gnode_upper; 11562306a36Sopenharmony_ci uv_cpu_hub_info(cpu)->global_mmr_base = mmr_base; 11662306a36Sopenharmony_ci uv_cpu_hub_info(cpu)->coherency_domain_number = 0;/* ZZZ */ 11762306a36Sopenharmony_ci printk(KERN_DEBUG "UV cpu %d, nid %d\n", cpu, nid); 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci} 12062306a36Sopenharmony_ci 121