⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 acpi.c

📁 是关于linux2.5.1的完全源码
💻 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 Hewlett-Packard Co. *  Copyright (C) 2000 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> * * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * *  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/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 <asm/efi.h>#include <asm/io.h>#include <asm/iosapic.h>#include <asm/machvec.h>#include <asm/page.h>#include <asm/system.h>#define PREFIX			"ACPI: "asm (".weak iosapic_register_irq");asm (".weak iosapic_register_legacy_irq");asm (".weak iosapic_register_platform_irq");asm (".weak iosapic_init");asm (".weak iosapic_version");void (*pm_idle) (void);void (*pm_power_off) (void);/* * TBD: Should go away once we have an ACPI parser. */const char *acpi_get_sysname (void){#ifdef CONFIG_IA64_GENERIC	return "hpsim";#else# if defined (CONFIG_IA64_HP_SIM)	return "hpsim";# elif defined (CONFIG_IA64_SGI_SN1)	return "sn1";# 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_BOOT#define ACPI_MAX_PLATFORM_IRQS	256/* Array to record platform interrupt vectors for generic interrupt routing. */int platform_irq_list[ACPI_MAX_PLATFORM_IRQS];/* * Interrupt routing API for device drivers.  Provides interrupt vector for * a generic platform event.  Currently only CPEI is implemented. */intacpi_request_vector (u32 int_type){	int vector = -1;	if (int_type < ACPI_MAX_PLATFORM_IRQS) {		/* correctable platform error interrupt */		vector = platform_irq_list[int_type];	} else		printk("acpi_request_vector(): invalid interrupt type\n");	return vector;}/* --------------------------------------------------------------------------                            Boot-time Table Parsing   -------------------------------------------------------------------------- */static int			total_cpus __initdata;static int			available_cpus __initdata;struct acpi_table_madt *	acpi_madt __initdata;static int __initacpi_parse_lapic_addr_ovr (acpi_table_entry_header *header){	struct acpi_table_lapic_addr_ovr *lapic = NULL;	lapic = (struct acpi_table_lapic_addr_ovr *) header;	if (!lapic)		return -EINVAL;	acpi_table_print_madt_entry(header);	if (lapic->address) {		iounmap((void *) ipi_base_addr);		ipi_base_addr = (unsigned long) ioremap(lapic->address, 0);	}	return 0;}static int __initacpi_parse_lsapic (acpi_table_entry_header *header){	struct acpi_table_lsapic *lsapic = NULL;	lsapic = (struct acpi_table_lsapic *) header;	if (!lsapic)		return -EINVAL;	acpi_table_print_madt_entry(header);	printk("CPU %d (0x%04x)", total_cpus, (lsapic->id << 8) | lsapic->eid);	if (lsapic->flags.enabled) {		available_cpus++;		printk(" enabled");#ifdef CONFIG_SMP		smp_boot_data.cpu_phys_id[total_cpus] = (lsapic->id << 8) | lsapic->eid;		if (hard_smp_processor_id() == smp_boot_data.cpu_phys_id[total_cpus])			printk(" (BSP)");#endif	}	else {		printk(" disabled");#ifdef CONFIG_SMP		smp_boot_data.cpu_phys_id[total_cpus] = -1;#endif	}	printk("\n");	total_cpus++;	return 0;}static int __initacpi_parse_lapic_nmi (acpi_table_entry_header *header){	struct acpi_table_lapic_nmi *lacpi_nmi = NULL;	lacpi_nmi = (struct acpi_table_lapic_nmi*) header;	if (!lacpi_nmi)		return -EINVAL;	acpi_table_print_madt_entry(header);	/* TBD: Support lapic_nmi entries */	return 0;}static int __initacpi_find_iosapic (int global_vector, u32 *irq_base, char **iosapic_address){	struct acpi_table_iosapic *iosapic = NULL;	int ver = 0;	int max_pin = 0;	char *p = 0;	char *end = 0;	if (!irq_base || !iosapic_address)		return -ENODEV;	p = (char *) (acpi_madt + 1);	end = p + (acpi_madt->header.length - sizeof(struct acpi_table_madt));	while (p < end) {		if (*p == ACPI_MADT_IOSAPIC) {			iosapic = (struct acpi_table_iosapic *) p;			*irq_base = iosapic->global_irq_base;			*iosapic_address = ioremap(iosapic->address, 0);			ver = iosapic_version(*iosapic_address);			max_pin = (ver >> 16) & 0xff;			if ((global_vector - *irq_base) <= max_pin)				return 0;	/* Found it! */		}		p += p[1];	}	return -ENODEV;}static int __initacpi_parse_iosapic (acpi_table_entry_header *header){	struct acpi_table_iosapic *iosapic;	iosapic = (struct acpi_table_iosapic *) header;	if (!iosapic)		return -EINVAL;	acpi_table_print_madt_entry(header);	if (iosapic_init) {#ifndef CONFIG_ITANIUM		/* PCAT_COMPAT flag indicates dual-8259 setup */		iosapic_init(iosapic->address, iosapic->global_irq_base,			     acpi_madt->flags.pcat_compat);#else		/* Firmware on old Itanium systems is broken */		iosapic_init(iosapic->address, iosapic->global_irq_base, 1);#endif	}	return 0;}static int __initacpi_parse_plat_int_src (acpi_table_entry_header *header){	struct acpi_table_plat_int_src *plintsrc = NULL;	int vector = 0;	u32 irq_base = 0;	char *iosapic_address = NULL;	plintsrc = (struct acpi_table_plat_int_src *) header;	if (!plintsrc)		return -EINVAL;	acpi_table_print_madt_entry(header);	if (!iosapic_register_platform_irq) {		printk(KERN_WARNING PREFIX "No ACPI platform IRQ support\n");		return -ENODEV;	}	if (0 != acpi_find_iosapic(plintsrc->global_irq, &irq_base, &iosapic_address)) {		printk(KERN_WARNING PREFIX "IOSAPIC not found\n");		return -ENODEV;	}	/*	 * Get vector assignment for this IRQ, set attributes, and program the	 * IOSAPIC routing table.	 */	vector = iosapic_register_platform_irq (plintsrc->type,						plintsrc->global_irq,						plintsrc->iosapic_vector,						plintsrc->eid,						plintsrc->id,						(plintsrc->flags.polarity == 1) ? 1 : 0,						(plintsrc->flags.trigger == 1) ? 1 : 0,						irq_base,						iosapic_address);	platform_irq_list[plintsrc->type] = vector;	return 0;}static int __initacpi_parse_int_src_ovr (acpi_table_entry_header *header){	struct acpi_table_int_src_ovr *p = NULL;	p = (struct acpi_table_int_src_ovr *) header;	if (!p)		return -EINVAL;	acpi_table_print_madt_entry(header);	/* Ignore if the platform doesn't support overrides */	if (!iosapic_register_legacy_irq)		return 0;	iosapic_register_legacy_irq(p->bus_irq, p->global_irq,		(p->flags.polarity == 1) ? 1 : 0,		(p->flags.trigger == 1) ? 1 : 0);	return 0;}static int __initacpi_parse_nmi_src (acpi_table_entry_header *header){	struct acpi_table_nmi_src *nmi_src = NULL;	nmi_src = (struct acpi_table_nmi_src*) header;	if (!nmi_src)		return -EINVAL;	acpi_table_print_madt_entry(header);	/* TBD: Support nimsrc entries */	return 0;}static int __initacpi_parse_madt (unsigned long phys_addr, unsigned long size){	int i = 0;	if (!phys_addr || !size)		return -EINVAL;	acpi_madt = (struct acpi_table_madt *) __va(phys_addr);	if (!acpi_madt) {		printk(KERN_WARNING PREFIX "Unable to map MADT\n");		return -ENODEV;	}	/* Initialize platform interrupt vector array */	for (i = 0; i < ACPI_MAX_PLATFORM_IRQS; i++)		platform_irq_list[i] = -1;	/* Get base address of IPI Message Block */	if (acpi_madt->lapic_address)		ipi_base_addr = (unsigned long)			ioremap(acpi_madt->lapic_address, 0);	printk(KERN_INFO PREFIX "Local APIC address 0x%lx\n", ipi_base_addr);	return 0;}int __initacpi_find_rsdp (unsigned long *rsdp_phys){	if (!rsdp_phys)		return -EINVAL;	if (efi.acpi20) {		(*rsdp_phys) = __pa(efi.acpi20);		return 0;	}	else if (efi.acpi) {		printk(KERN_WARNING PREFIX "v1.0/r0.71 tables no longer supported\n");	}	return -ENODEV;}#ifdef CONFIG_SERIAL_ACPI#include <linux/acpi_serial.h>static int __initacpi_parse_spcr (unsigned long phys_addr, unsigned long size){	acpi_ser_t *spcr = NULL;	unsigned long global_int = 0;	if (!phys_addr || !size)		return -EINVAL;	if (!iosapic_register_irq)		return -ENODEV;	/*	 * ACPI is able to describe serial ports that live at non-standard	 * memory addresses and use non-standard interrupts, either via	 * direct SAPIC mappings or via PCI interrupts.  We handle interrupt	 * routing for SAPIC-based (non-PCI) devices here.  Interrupt routing	 * for PCI devices will be handled when processing the PCI Interrupt	 * Routing Table (PRT).	 */	spcr = (acpi_ser_t *) __va(phys_addr);	if (!spcr) {		printk(KERN_WARNING PREFIX "Unable to map SPCR\n");		return -ENODEV;	}	setup_serial_acpi(spcr);	if (spcr->length < sizeof(acpi_ser_t))		/* Table not long enough for full info, thus no interrupt */		return -ENODEV;	if ((spcr->base_addr.space_id != ACPI_SERIAL_PCICONF_SPACE) &&	    (spcr->int_type == ACPI_SERIAL_INT_SAPIC))	{		u32 irq_base = 0;		char *iosapic_address = NULL;		int vector = 0;		/* We have a UART in memory space with an SAPIC interrupt */		global_int = (  (spcr->global_int[3] << 24) |				(spcr->global_int[2] << 16) |				(spcr->global_int[1] << 8)  |				(spcr->global_int[0])  );		/* Which iosapic does this IRQ belong to? */		if (0 == acpi_find_iosapic(global_int, &irq_base, &iosapic_address)) {			vector = iosapic_register_irq (global_int, 1, 1,						       irq_base, iosapic_address);		}	}	return 0;}#endif /*CONFIG_SERIAL_ACPI*/int __initacpi_boot_init (char *cmdline){	int result = 0;	/* Initialize the ACPI boot-time table parser */	result = acpi_table_init(cmdline);	if (0 != result)		return result;	/*	 * MADT	 * ----	 * Parse the Multiple APIC Description Table (MADT), if exists.	 * Note that this table provides platform SMP configuration	 * information -- the successor to MPS tables.	 */	result = acpi_table_parse(ACPI_APIC, acpi_parse_madt);	if (1 > result)		return result;	/* Local APIC */	result = acpi_table_parse_madt(ACPI_MADT_LAPIC_ADDR_OVR, acpi_parse_lapic_addr_ovr);	if (0 > result) {		printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n");		return result;	}	result = acpi_table_parse_madt(ACPI_MADT_LSAPIC, acpi_parse_lsapic);	if (1 > result) {		printk(KERN_ERR PREFIX "Error parsing MADT - no LAPIC entries!\n");		return -ENODEV;	}	result = acpi_table_parse_madt(ACPI_MADT_LAPIC_NMI, acpi_parse_lapic_nmi);	if (0 > result) {		printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n");		return result;	}	/* I/O APIC */	result = acpi_table_parse_madt(ACPI_MADT_IOSAPIC, acpi_parse_iosapic);	if (1 > result) {		printk(KERN_ERR PREFIX "Error parsing MADT - no IOAPIC entries!\n");		return ((result == 0) ? -ENODEV : result);	}	/* System-Level Interrupt Routing */	result = acpi_table_parse_madt(ACPI_MADT_PLAT_INT_SRC, acpi_parse_plat_int_src);	if (0 > result) {		printk(KERN_ERR PREFIX "Error parsing platform interrupt source entry\n");		return result;	}	result = acpi_table_parse_madt(ACPI_MADT_INT_SRC_OVR, acpi_parse_int_src_ovr);	if (0 > result) {		printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n");		return result;	}	result = acpi_table_parse_madt(ACPI_MADT_NMI_SRC, acpi_parse_nmi_src);	if (0 > result) {		printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n");		return result;	}#ifdef CONFIG_SERIAL_ACPI	/*	 * TBD: Need phased approach to table parsing (only do those absolutely	 *      required during boot-up).  Recommend expanding concept of fix-	 *      feature devices (LDM) to include table-based devices such as	 *      serial ports, EC, SMBus, etc.	 */	acpi_table_parse(ACPI_SPCR, acpi_parse_spcr);#endif /*CONFIG_SERIAL_ACPI*/#ifdef CONFIG_SMP	if (available_cpus == 0) {		printk("ACPI: Found 0 CPUS; assuming 1\n");		available_cpus = 1; /* We've got at least one of these, no? */	}	smp_boot_data.cpu_count = total_cpus;#endif	/* Make boot-up look pretty */	printk("%d CPUs available, %d CPUs total\n", available_cpus, total_cpus);	return 0;}/* --------------------------------------------------------------------------                             PCI Interrupt Routing   -------------------------------------------------------------------------- */int __initacpi_get_prt (struct pci_vector_struct **vectors, int *count){	struct pci_vector_struct *vector = NULL;	struct list_head *node = NULL;	struct acpi_prt_entry *entry = NULL;	int i = 0;	if (!vectors || !count)		return -EINVAL;	*vectors = NULL;	*count = 0;	if (acpi_prts.count < 0) {		printk(KERN_ERR PREFIX "No PCI IRQ routing entries\n");		return -ENODEV;	}	/* Allocate vectors */	*vectors = kmalloc(sizeof(struct pci_vector_struct) * acpi_prts.count, GFP_KERNEL);	if (!(*vectors))		return -ENOMEM;	/* Convert PRT entries to IOSAPIC PCI vectors */	vector = *vectors;	list_for_each(node, &acpi_prts.entries) {		entry = (struct acpi_prt_entry *)node;		vector[i].bus    = (u16) entry->id.bus;		vector[i].pci_id = (u32) entry->id.dev << 16 | 0xffff;		vector[i].pin    = (u8)  entry->id.pin;		vector[i].irq    = (u8)  entry->source.index;		i++;	}	*count = acpi_prts.count;	return 0;}/* Assume IA64 always use I/O SAPIC */int __initacpi_get_interrupt_model (int *type){        if (!type)                return -EINVAL;	*type = ACPI_INT_MODEL_IOSAPIC;        return 0;}#endif /* CONFIG_ACPI_BOOT */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -