📄 acpi.c
字号:
/* * acpi.c - Architecture-Specific Low-Level ACPI Support * * Copyright (C) 1999 VA Linux Systems * Copyright (C) 1999,2000 Walt Drummond <drummond@valinux.com> * Copyright (C) 2000, 2002-2003 Hewlett-Packard Co. * David Mosberger-Tang <davidm@hpl.hp.com> * Copyright (C) 2000 Intel Corp. * Copyright (C) 2000,2001 J.I. Lee <jung-ik.lee@intel.com> * Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> * Copyright (C) 2001 Jenna Hall <jenna.s.hall@intel.com> * Copyright (C) 2001 Takayoshi Kochi <t-kochi@bq.jp.nec.com> * Copyright (C) 2002 Erich Focht <efocht@ess.nec.de> * Copyright (C) 2004 Ashok Raj <ashok.raj@intel.com> * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/smp.h>#include <linux/string.h>#include <linux/types.h>#include <linux/irq.h>#include <linux/acpi.h>#include <linux/efi.h>#include <linux/mmzone.h>#include <linux/nodemask.h>#include <asm/io.h>#include <asm/iosapic.h>#include <asm/machvec.h>#include <asm/page.h>#include <asm/system.h>#include <asm/numa.h>#include <asm/sal.h>#include <asm/cyclone.h>#define BAD_MADT_ENTRY(entry, end) ( \ (!entry) || (unsigned long)entry + sizeof(*entry) > end || \ ((acpi_table_entry_header *)entry)->length != sizeof(*entry))#define PREFIX "ACPI: "void (*pm_idle) (void);EXPORT_SYMBOL(pm_idle);void (*pm_power_off) (void);EXPORT_SYMBOL(pm_power_off);unsigned char acpi_kbd_controller_present = 1;unsigned char acpi_legacy_devices;static unsigned int __initdata acpi_madt_rev;unsigned int acpi_cpei_override;unsigned int acpi_cpei_phys_cpuid;#define MAX_SAPICS 256u16 ia64_acpiid_to_sapicid[MAX_SAPICS] = {[0 ... MAX_SAPICS - 1] = -1 };EXPORT_SYMBOL(ia64_acpiid_to_sapicid);const char *acpi_get_sysname(void){#ifdef CONFIG_IA64_GENERIC unsigned long rsdp_phys; struct acpi20_table_rsdp *rsdp; struct acpi_table_xsdt *xsdt; struct acpi_table_header *hdr; rsdp_phys = acpi_find_rsdp(); if (!rsdp_phys) { printk(KERN_ERR "ACPI 2.0 RSDP not found, default to \"dig\"\n"); return "dig"; } rsdp = (struct acpi20_table_rsdp *)__va(rsdp_phys); if (strncmp(rsdp->signature, RSDP_SIG, sizeof(RSDP_SIG) - 1)) { printk(KERN_ERR "ACPI 2.0 RSDP signature incorrect, default to \"dig\"\n"); return "dig"; } xsdt = (struct acpi_table_xsdt *)__va(rsdp->xsdt_address); hdr = &xsdt->header; if (strncmp(hdr->signature, XSDT_SIG, sizeof(XSDT_SIG) - 1)) { printk(KERN_ERR "ACPI 2.0 XSDT signature incorrect, default to \"dig\"\n"); return "dig"; } if (!strcmp(hdr->oem_id, "HP")) { return "hpzx1"; } else if (!strcmp(hdr->oem_id, "SGI")) { return "sn2"; } return "dig";#else# if defined (CONFIG_IA64_HP_SIM) return "hpsim";# elif defined (CONFIG_IA64_HP_ZX1) return "hpzx1";# elif defined (CONFIG_IA64_HP_ZX1_SWIOTLB) return "hpzx1_swiotlb";# elif defined (CONFIG_IA64_SGI_SN2) return "sn2";# elif defined (CONFIG_IA64_DIG) return "dig";# else# error Unknown platform. Fix acpi.c.# endif#endif}#ifdef CONFIG_ACPI#define ACPI_MAX_PLATFORM_INTERRUPTS 256/* Array to record platform interrupt vectors for generic interrupt routing. */int platform_intr_list[ACPI_MAX_PLATFORM_INTERRUPTS] = { [0 ... ACPI_MAX_PLATFORM_INTERRUPTS - 1] = -1};enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_IOSAPIC;/* * Interrupt routing API for device drivers. Provides interrupt vector for * a generic platform event. Currently only CPEI is implemented. */int acpi_request_vector(u32 int_type){ int vector = -1; if (int_type < ACPI_MAX_PLATFORM_INTERRUPTS) { /* corrected platform error interrupt */ vector = platform_intr_list[int_type]; } else printk(KERN_ERR "acpi_request_vector(): invalid interrupt type\n"); return vector;}char *__acpi_map_table(unsigned long phys_addr, unsigned long size){ return __va(phys_addr);}/* -------------------------------------------------------------------------- Boot-time Table Parsing -------------------------------------------------------------------------- */static int total_cpus __initdata;static int available_cpus __initdata;struct acpi_table_madt *acpi_madt __initdata;static u8 has_8259;static int __initacpi_parse_lapic_addr_ovr(acpi_table_entry_header * header, const unsigned long end){ struct acpi_table_lapic_addr_ovr *lapic; lapic = (struct acpi_table_lapic_addr_ovr *)header; if (BAD_MADT_ENTRY(lapic, end)) return -EINVAL; if (lapic->address) { iounmap(ipi_base_addr); ipi_base_addr = ioremap(lapic->address, 0); } return 0;}static int __initacpi_parse_lsapic(acpi_table_entry_header * header, const unsigned long end){ struct acpi_table_lsapic *lsapic; lsapic = (struct acpi_table_lsapic *)header; if (BAD_MADT_ENTRY(lsapic, end)) return -EINVAL; if (lsapic->flags.enabled) {#ifdef CONFIG_SMP smp_boot_data.cpu_phys_id[available_cpus] = (lsapic->id << 8) | lsapic->eid;#endif ia64_acpiid_to_sapicid[lsapic->acpi_id] = (lsapic->id << 8) | lsapic->eid; ++available_cpus; } total_cpus++; return 0;}static int __initacpi_parse_lapic_nmi(acpi_table_entry_header * header, const unsigned long end){ struct acpi_table_lapic_nmi *lacpi_nmi; lacpi_nmi = (struct acpi_table_lapic_nmi *)header; if (BAD_MADT_ENTRY(lacpi_nmi, end)) return -EINVAL; /* TBD: Support lapic_nmi entries */ return 0;}static int __initacpi_parse_iosapic(acpi_table_entry_header * header, const unsigned long end){ struct acpi_table_iosapic *iosapic; iosapic = (struct acpi_table_iosapic *)header; if (BAD_MADT_ENTRY(iosapic, end)) return -EINVAL; return iosapic_init(iosapic->address, iosapic->global_irq_base);}static int __initacpi_parse_plat_int_src(acpi_table_entry_header * header, const unsigned long end){ struct acpi_table_plat_int_src *plintsrc; int vector; plintsrc = (struct acpi_table_plat_int_src *)header; if (BAD_MADT_ENTRY(plintsrc, end)) return -EINVAL; /* * Get vector assignment for this interrupt, set attributes, * and program the IOSAPIC routing table. */ vector = iosapic_register_platform_intr(plintsrc->type, plintsrc->global_irq, plintsrc->iosapic_vector, plintsrc->eid, plintsrc->id, (plintsrc->flags.polarity == 1) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW, (plintsrc->flags.trigger == 1) ? IOSAPIC_EDGE : IOSAPIC_LEVEL); platform_intr_list[plintsrc->type] = vector; if (acpi_madt_rev > 1) { acpi_cpei_override = plintsrc->plint_flags.cpei_override_flag; } /* * Save the physical id, so we can check when its being removed */ acpi_cpei_phys_cpuid = ((plintsrc->id << 8) | (plintsrc->eid)) & 0xffff; return 0;}unsigned int can_cpei_retarget(void){ extern int cpe_vector; /* * Only if CPEI is supported and the override flag * is present, otherwise return that its re-targettable * if we are in polling mode. */ if (cpe_vector > 0 && !acpi_cpei_override) return 0; else return 1;}unsigned int is_cpu_cpei_target(unsigned int cpu){ unsigned int logical_id; logical_id = cpu_logical_id(acpi_cpei_phys_cpuid); if (logical_id == cpu) return 1; else return 0;}void set_cpei_target_cpu(unsigned int cpu){ acpi_cpei_phys_cpuid = cpu_physical_id(cpu);}unsigned int get_cpei_target_cpu(void){ return acpi_cpei_phys_cpuid;}static int __initacpi_parse_int_src_ovr(acpi_table_entry_header * header, const unsigned long end){ struct acpi_table_int_src_ovr *p; p = (struct acpi_table_int_src_ovr *)header; if (BAD_MADT_ENTRY(p, end)) return -EINVAL; iosapic_override_isa_irq(p->bus_irq, p->global_irq, (p->flags.polarity == 1) ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW, (p->flags.trigger == 1) ? IOSAPIC_EDGE : IOSAPIC_LEVEL); return 0;}static int __initacpi_parse_nmi_src(acpi_table_entry_header * header, const unsigned long end){ struct acpi_table_nmi_src *nmi_src; nmi_src = (struct acpi_table_nmi_src *)header; if (BAD_MADT_ENTRY(nmi_src, end)) return -EINVAL; /* TBD: Support nimsrc entries */ return 0;}static void __init acpi_madt_oem_check(char *oem_id, char *oem_table_id){ if (!strncmp(oem_id, "IBM", 3) && (!strncmp(oem_table_id, "SERMOW", 6))) { /* * Unfortunately ITC_DRIFT is not yet part of the * official SAL spec, so the ITC_DRIFT bit is not * set by the BIOS on this hardware. */ sal_platform_features |= IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT; cyclone_setup(); }}static int __init acpi_parse_madt(unsigned long phys_addr, unsigned long size){ if (!phys_addr || !size) return -EINVAL; acpi_madt = (struct acpi_table_madt *)__va(phys_addr); acpi_madt_rev = acpi_madt->header.revision; /* remember the value for reference after free_initmem() */#ifdef CONFIG_ITANIUM has_8259 = 1; /* Firmware on old Itanium systems is broken */#else has_8259 = acpi_madt->flags.pcat_compat;#endif iosapic_system_init(has_8259); /* Get base address of IPI Message Block */ if (acpi_madt->lapic_address) ipi_base_addr = ioremap(acpi_madt->lapic_address, 0); printk(KERN_INFO PREFIX "Local APIC address %p\n", ipi_base_addr); acpi_madt_oem_check(acpi_madt->header.oem_id, acpi_madt->header.oem_table_id); return 0;}#ifdef CONFIG_ACPI_NUMA#undef SLIT_DEBUG#define PXM_FLAG_LEN ((MAX_PXM_DOMAINS + 1)/32)static int __initdata srat_num_cpus; /* number of cpus */static u32 __devinitdata pxm_flag[PXM_FLAG_LEN];#define pxm_bit_set(bit) (set_bit(bit,(void *)pxm_flag))#define pxm_bit_test(bit) (test_bit(bit,(void *)pxm_flag))/* maps to convert between proximity domain and logical node ID */int __devinitdata pxm_to_nid_map[MAX_PXM_DOMAINS];int __initdata nid_to_pxm_map[MAX_NUMNODES];static struct acpi_table_slit __initdata *slit_table;/* * ACPI 2.0 SLIT (System Locality Information Table) * http://devresource.hp.com/devresource/Docs/TechPapers/IA64/slit.pdf */void __init acpi_numa_slit_init(struct acpi_table_slit *slit){ u32 len; len = sizeof(struct acpi_table_header) + 8 + slit->localities * slit->localities; if (slit->header.length != len) { printk(KERN_ERR "ACPI 2.0 SLIT: size mismatch: %d expected, %d actual\n", len, slit->header.length); memset(numa_slit, 10, sizeof(numa_slit)); return; } slit_table = slit;}void __initacpi_numa_processor_affinity_init(struct acpi_table_processor_affinity *pa){ /* record this node in proximity bitmap */ pxm_bit_set(pa->proximity_domain); node_cpuid[srat_num_cpus].phys_id = (pa->apic_id << 8) | (pa->lsapic_eid); /* nid should be overridden as logical node id later */ node_cpuid[srat_num_cpus].nid = pa->proximity_domain; srat_num_cpus++;}void __initacpi_numa_memory_affinity_init(struct acpi_table_memory_affinity *ma){ unsigned long paddr, size; u8 pxm; struct node_memblk_s *p, *q, *pend; pxm = ma->proximity_domain; /* fill node memory chunk structure */ paddr = ma->base_addr_hi; paddr = (paddr << 32) | ma->base_addr_lo; size = ma->length_hi; size = (size << 32) | ma->length_lo;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -