122246614SJack Steiner /*
222246614SJack Steiner * This file is subject to the terms and conditions of the GNU General Public
322246614SJack Steiner * License. See the file "COPYING" in the main directory of this archive
422246614SJack Steiner * for more details.
522246614SJack Steiner *
622246614SJack Steiner * SGI UV Core Functions
722246614SJack Steiner *
822246614SJack Steiner * Copyright (C) 2008 Silicon Graphics, Inc. All rights reserved.
922246614SJack Steiner */
1022246614SJack Steiner
11*df41017eSChristoph Hellwig #include <linux/acpi.h>
12*df41017eSChristoph Hellwig #include <linux/efi.h>
1322246614SJack Steiner #include <linux/module.h>
1422246614SJack Steiner #include <linux/percpu.h>
15*df41017eSChristoph Hellwig #include <asm/uv/uv.h>
1622246614SJack Steiner #include <asm/uv/uv_mmrs.h>
1722246614SJack Steiner #include <asm/uv/uv_hub.h>
1822246614SJack Steiner
19*df41017eSChristoph Hellwig bool ia64_is_uv;
20*df41017eSChristoph Hellwig EXPORT_SYMBOL_GPL(ia64_is_uv);
21*df41017eSChristoph Hellwig
2222246614SJack Steiner DEFINE_PER_CPU(struct uv_hub_info_s, __uv_hub_info);
2322246614SJack Steiner EXPORT_PER_CPU_SYMBOL_GPL(__uv_hub_info);
2422246614SJack Steiner
2522246614SJack Steiner struct redir_addr {
2622246614SJack Steiner unsigned long redirect;
2722246614SJack Steiner unsigned long alias;
2822246614SJack Steiner };
2922246614SJack Steiner
3022246614SJack Steiner #define DEST_SHIFT UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR_DEST_BASE_SHFT
3122246614SJack Steiner
3222246614SJack Steiner static __initdata struct redir_addr redir_addrs[] = {
3322246614SJack Steiner {UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_0_MMR, UVH_SI_ALIAS0_OVERLAY_CONFIG},
3422246614SJack Steiner {UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_1_MMR, UVH_SI_ALIAS1_OVERLAY_CONFIG},
3522246614SJack Steiner {UVH_RH_GAM_ALIAS210_REDIRECT_CONFIG_2_MMR, UVH_SI_ALIAS2_OVERLAY_CONFIG},
3622246614SJack Steiner };
3722246614SJack Steiner
get_lowmem_redirect(unsigned long * base,unsigned long * size)3822246614SJack Steiner static __init void get_lowmem_redirect(unsigned long *base, unsigned long *size)
3922246614SJack Steiner {
4022246614SJack Steiner union uvh_si_alias0_overlay_config_u alias;
4122246614SJack Steiner union uvh_rh_gam_alias210_redirect_config_2_mmr_u redirect;
4222246614SJack Steiner int i;
4322246614SJack Steiner
4422246614SJack Steiner for (i = 0; i < ARRAY_SIZE(redir_addrs); i++) {
4522246614SJack Steiner alias.v = uv_read_local_mmr(redir_addrs[i].alias);
4622246614SJack Steiner if (alias.s.base == 0) {
4722246614SJack Steiner *size = (1UL << alias.s.m_alias);
4822246614SJack Steiner redirect.v = uv_read_local_mmr(redir_addrs[i].redirect);
4922246614SJack Steiner *base = (unsigned long)redirect.s.dest_base << DEST_SHIFT;
5022246614SJack Steiner return;
5122246614SJack Steiner }
5222246614SJack Steiner }
5322246614SJack Steiner BUG();
5422246614SJack Steiner }
5522246614SJack Steiner
uv_probe_system_type(void)56*df41017eSChristoph Hellwig void __init uv_probe_system_type(void)
57*df41017eSChristoph Hellwig {
58*df41017eSChristoph Hellwig struct acpi_table_rsdp *rsdp;
59*df41017eSChristoph Hellwig struct acpi_table_xsdt *xsdt;
60*df41017eSChristoph Hellwig
61*df41017eSChristoph Hellwig if (efi.acpi20 == EFI_INVALID_TABLE_ADDR) {
62*df41017eSChristoph Hellwig pr_err("ACPI 2.0 RSDP not found.\n");
63*df41017eSChristoph Hellwig return;
64*df41017eSChristoph Hellwig }
65*df41017eSChristoph Hellwig
66*df41017eSChristoph Hellwig rsdp = (struct acpi_table_rsdp *)__va(efi.acpi20);
67*df41017eSChristoph Hellwig if (strncmp(rsdp->signature, ACPI_SIG_RSDP, sizeof(ACPI_SIG_RSDP) - 1)) {
68*df41017eSChristoph Hellwig pr_err("ACPI 2.0 RSDP signature incorrect.\n");
69*df41017eSChristoph Hellwig return;
70*df41017eSChristoph Hellwig }
71*df41017eSChristoph Hellwig
72*df41017eSChristoph Hellwig xsdt = (struct acpi_table_xsdt *)__va(rsdp->xsdt_physical_address);
73*df41017eSChristoph Hellwig if (strncmp(xsdt->header.signature, ACPI_SIG_XSDT,
74*df41017eSChristoph Hellwig sizeof(ACPI_SIG_XSDT) - 1)) {
75*df41017eSChristoph Hellwig pr_err("ACPI 2.0 XSDT signature incorrect.\n");
76*df41017eSChristoph Hellwig return;
77*df41017eSChristoph Hellwig }
78*df41017eSChristoph Hellwig
79*df41017eSChristoph Hellwig if (!strcmp(xsdt->header.oem_id, "SGI") &&
80*df41017eSChristoph Hellwig !strcmp(xsdt->header.oem_table_id + 4, "UV"))
81*df41017eSChristoph Hellwig ia64_is_uv = true;
82*df41017eSChristoph Hellwig }
83*df41017eSChristoph Hellwig
uv_setup(char ** cmdline_p)8422246614SJack Steiner void __init uv_setup(char **cmdline_p)
8522246614SJack Steiner {
8622246614SJack Steiner union uvh_si_addr_map_config_u m_n_config;
8722246614SJack Steiner union uvh_node_id_u node_id;
8822246614SJack Steiner unsigned long gnode_upper;
8922246614SJack Steiner int nid, cpu, m_val, n_val;
9022246614SJack Steiner unsigned long mmr_base, lowmem_redir_base, lowmem_redir_size;
9122246614SJack Steiner
9222246614SJack Steiner get_lowmem_redirect(&lowmem_redir_base, &lowmem_redir_size);
9322246614SJack Steiner node_id.v = uv_read_local_mmr(UVH_NODE_ID);
9422246614SJack Steiner m_n_config.v = uv_read_local_mmr(UVH_SI_ADDR_MAP_CONFIG);
951164e757SChristoph Hellwig mmr_base = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR) &
9622246614SJack Steiner ~UV_MMR_ENABLE;
9722246614SJack Steiner
9822246614SJack Steiner m_val = m_n_config.s.m_skt;
9922246614SJack Steiner n_val = m_n_config.s.n_skt;
10022246614SJack Steiner printk(KERN_DEBUG "UV: global MMR base 0x%lx\n", mmr_base);
10122246614SJack Steiner
10222246614SJack Steiner gnode_upper = (((unsigned long)node_id.s.node_id) &
10322246614SJack Steiner ~((1 << n_val) - 1)) << m_val;
10422246614SJack Steiner
10522246614SJack Steiner for_each_present_cpu(cpu) {
10622246614SJack Steiner nid = cpu_to_node(cpu);
10722246614SJack Steiner uv_cpu_hub_info(cpu)->lowmem_remap_base = lowmem_redir_base;
10822246614SJack Steiner uv_cpu_hub_info(cpu)->lowmem_remap_top =
10922246614SJack Steiner lowmem_redir_base + lowmem_redir_size;
11022246614SJack Steiner uv_cpu_hub_info(cpu)->m_val = m_val;
111b6dcefdeSRoel Kluin uv_cpu_hub_info(cpu)->n_val = n_val;
11222246614SJack Steiner uv_cpu_hub_info(cpu)->pnode_mask = (1 << n_val) -1;
11322246614SJack Steiner uv_cpu_hub_info(cpu)->gpa_mask = (1 << (m_val + n_val)) - 1;
11422246614SJack Steiner uv_cpu_hub_info(cpu)->gnode_upper = gnode_upper;
11522246614SJack Steiner uv_cpu_hub_info(cpu)->global_mmr_base = mmr_base;
11622246614SJack Steiner uv_cpu_hub_info(cpu)->coherency_domain_number = 0;/* ZZZ */
11722246614SJack Steiner printk(KERN_DEBUG "UV cpu %d, nid %d\n", cpu, nid);
11822246614SJack Steiner }
11922246614SJack Steiner }
12022246614SJack Steiner
121