linux/arch/arm64/kernel/acpi.c
<<
>>
Prefs
   1/*
   2 *  ARM64 Specific Low-Level ACPI Boot Support
   3 *
   4 *  Copyright (C) 2013-2014, Linaro Ltd.
   5 *      Author: Al Stone <al.stone@linaro.org>
   6 *      Author: Graeme Gregory <graeme.gregory@linaro.org>
   7 *      Author: Hanjun Guo <hanjun.guo@linaro.org>
   8 *      Author: Tomasz Nowicki <tomasz.nowicki@linaro.org>
   9 *      Author: Naresh Bhat <naresh.bhat@linaro.org>
  10 *
  11 *  This program is free software; you can redistribute it and/or modify
  12 *  it under the terms of the GNU General Public License version 2 as
  13 *  published by the Free Software Foundation.
  14 */
  15
  16#define pr_fmt(fmt) "ACPI: " fmt
  17
  18#include <linux/acpi.h>
  19#include <linux/bootmem.h>
  20#include <linux/cpumask.h>
  21#include <linux/init.h>
  22#include <linux/irq.h>
  23#include <linux/irqdomain.h>
  24#include <linux/memblock.h>
  25#include <linux/of_fdt.h>
  26#include <linux/smp.h>
  27
  28#include <asm/cputype.h>
  29#include <asm/cpu_ops.h>
  30#include <asm/smp_plat.h>
  31
  32int acpi_noirq = 1;             /* skip ACPI IRQ initialization */
  33int acpi_disabled = 1;
  34EXPORT_SYMBOL(acpi_disabled);
  35
  36int acpi_pci_disabled = 1;      /* skip ACPI PCI scan and IRQ initialization */
  37EXPORT_SYMBOL(acpi_pci_disabled);
  38
  39static bool param_acpi_off __initdata;
  40static bool param_acpi_force __initdata;
  41
  42static int __init parse_acpi(char *arg)
  43{
  44        if (!arg)
  45                return -EINVAL;
  46
  47        /* "acpi=off" disables both ACPI table parsing and interpreter */
  48        if (strcmp(arg, "off") == 0)
  49                param_acpi_off = true;
  50        else if (strcmp(arg, "force") == 0) /* force ACPI to be enabled */
  51                param_acpi_force = true;
  52        else
  53                return -EINVAL; /* Core will print when we return error */
  54
  55        return 0;
  56}
  57early_param("acpi", parse_acpi);
  58
  59static int __init dt_scan_depth1_nodes(unsigned long node,
  60                                       const char *uname, int depth,
  61                                       void *data)
  62{
  63        /*
  64         * Return 1 as soon as we encounter a node at depth 1 that is
  65         * not the /chosen node.
  66         */
  67        if (depth == 1 && (strcmp(uname, "chosen") != 0))
  68                return 1;
  69        return 0;
  70}
  71
  72/*
  73 * __acpi_map_table() will be called before page_init(), so early_ioremap()
  74 * or early_memremap() should be called here to for ACPI table mapping.
  75 */
  76char *__init __acpi_map_table(unsigned long phys, unsigned long size)
  77{
  78        if (!size)
  79                return NULL;
  80
  81        return early_memremap(phys, size);
  82}
  83
  84void __init __acpi_unmap_table(char *map, unsigned long size)
  85{
  86        if (!map || !size)
  87                return;
  88
  89        early_memunmap(map, size);
  90}
  91
  92bool __init acpi_psci_present(void)
  93{
  94        return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_COMPLIANT;
  95}
  96
  97/* Whether HVC must be used instead of SMC as the PSCI conduit */
  98bool __init acpi_psci_use_hvc(void)
  99{
 100        return acpi_gbl_FADT.arm_boot_flags & ACPI_FADT_PSCI_USE_HVC;
 101}
 102
 103/*
 104 * acpi_fadt_sanity_check() - Check FADT presence and carry out sanity
 105 *                            checks on it
 106 *
 107 * Return 0 on success,  <0 on failure
 108 */
 109static int __init acpi_fadt_sanity_check(void)
 110{
 111        struct acpi_table_header *table;
 112        struct acpi_table_fadt *fadt;
 113        acpi_status status;
 114        acpi_size tbl_size;
 115        int ret = 0;
 116
 117        /*
 118         * FADT is required on arm64; retrieve it to check its presence
 119         * and carry out revision and ACPI HW reduced compliancy tests
 120         */
 121        status = acpi_get_table_with_size(ACPI_SIG_FADT, 0, &table, &tbl_size);
 122        if (ACPI_FAILURE(status)) {
 123                const char *msg = acpi_format_exception(status);
 124
 125                pr_err("Failed to get FADT table, %s\n", msg);
 126                return -ENODEV;
 127        }
 128
 129        fadt = (struct acpi_table_fadt *)table;
 130
 131        /*
 132         * Revision in table header is the FADT Major revision, and there
 133         * is a minor revision of FADT which was introduced by ACPI 5.1,
 134         * we only deal with ACPI 5.1 or newer revision to get GIC and SMP
 135         * boot protocol configuration data.
 136         */
 137        if (table->revision < 5 ||
 138           (table->revision == 5 && fadt->minor_revision < 1)) {
 139                pr_err("Unsupported FADT revision %d.%d, should be 5.1+\n",
 140                       table->revision, fadt->minor_revision);
 141                ret = -EINVAL;
 142                goto out;
 143        }
 144
 145        if (!(fadt->flags & ACPI_FADT_HW_REDUCED)) {
 146                pr_err("FADT not ACPI hardware reduced compliant\n");
 147                ret = -EINVAL;
 148        }
 149
 150out:
 151        /*
 152         * acpi_get_table_with_size() creates FADT table mapping that
 153         * should be released after parsing and before resuming boot
 154         */
 155        early_acpi_os_unmap_memory(table, tbl_size);
 156        return ret;
 157}
 158
 159/*
 160 * acpi_boot_table_init() called from setup_arch(), always.
 161 *      1. find RSDP and get its address, and then find XSDT
 162 *      2. extract all tables and checksums them all
 163 *      3. check ACPI FADT revision
 164 *      4. check ACPI FADT HW reduced flag
 165 *
 166 * We can parse ACPI boot-time tables such as MADT after
 167 * this function is called.
 168 *
 169 * On return ACPI is enabled if either:
 170 *
 171 * - ACPI tables are initialized and sanity checks passed
 172 * - acpi=force was passed in the command line and ACPI was not disabled
 173 *   explicitly through acpi=off command line parameter
 174 *
 175 * ACPI is disabled on function return otherwise
 176 */
 177void __init acpi_boot_table_init(void)
 178{
 179        /*
 180         * Enable ACPI instead of device tree unless
 181         * - ACPI has been disabled explicitly (acpi=off), or
 182         * - the device tree is not empty (it has more than just a /chosen node)
 183         *   and ACPI has not been force enabled (acpi=force)
 184         */
 185        if (param_acpi_off ||
 186            (!param_acpi_force && of_scan_flat_dt(dt_scan_depth1_nodes, NULL)))
 187                return;
 188
 189        /*
 190         * ACPI is disabled at this point. Enable it in order to parse
 191         * the ACPI tables and carry out sanity checks
 192         */
 193        enable_acpi();
 194
 195        /*
 196         * If ACPI tables are initialized and FADT sanity checks passed,
 197         * leave ACPI enabled and carry on booting; otherwise disable ACPI
 198         * on initialization error.
 199         * If acpi=force was passed on the command line it forces ACPI
 200         * to be enabled even if its initialization failed.
 201         */
 202        if (acpi_table_init() || acpi_fadt_sanity_check()) {
 203                pr_err("Failed to init ACPI tables\n");
 204                if (!param_acpi_force)
 205                        disable_acpi();
 206        }
 207}
 208
 209void __init acpi_gic_init(void)
 210{
 211        struct acpi_table_header *table;
 212        acpi_status status;
 213        acpi_size tbl_size;
 214        int err;
 215
 216        if (acpi_disabled)
 217                return;
 218
 219        status = acpi_get_table_with_size(ACPI_SIG_MADT, 0, &table, &tbl_size);
 220        if (ACPI_FAILURE(status)) {
 221                const char *msg = acpi_format_exception(status);
 222
 223                pr_err("Failed to get MADT table, %s\n", msg);
 224                return;
 225        }
 226
 227        err = gic_v2_acpi_init(table);
 228        if (err)
 229                pr_err("Failed to initialize GIC IRQ controller");
 230
 231        early_acpi_os_unmap_memory((char *)table, tbl_size);
 232}
 233