Commit b4f305dd authored by Andy Grover's avatar Andy Grover Committed by Linus Torvalds

[PATCH] ACPI patch 9/9

If you could only review one of the 9 patches, this would be the one.

- removes acpitable.c vestiges
- adds ACPI IRQ routing support to PCI (disableable via pci=noacpi option)
- adds code to get a <1MB page for sleep, and ACPI boot to setup.c
- allocates another page in the fixmap for ACPI
- changes driverfs a little to work better with ACPI.
parent f03ccc72
......@@ -14,6 +14,7 @@
#include <linux/mm.h>
#include <linux/irq.h>
#include <linux/acpi.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/config.h>
......@@ -30,6 +31,9 @@
/* Have we found an MP table */
int smp_found_config;
/* Have we found an ACPI MADT table */
int acpi_found_madt = 0;
/*
* Various Linux-internal data structures created from the
* MP-table.
......@@ -65,6 +69,19 @@ static unsigned int num_processors;
/* Bitmask of physically existing CPUs */
unsigned long phys_cpu_present_map;
/* ACPI MADT entry parsing functions */
#ifdef CONFIG_ACPI_BOOT
extern struct acpi_boot_flags acpi_boot;
#ifdef CONFIG_X86_LOCAL_APIC
extern int acpi_parse_lapic (acpi_table_entry_header *header);
extern int acpi_parse_lapic_addr_ovr (acpi_table_entry_header *header);
extern int acpi_parse_lapic_nmi (acpi_table_entry_header *header);
#endif /*CONFIG_X86_LOCAL_APIC*/
#ifdef CONFIG_X86_IO_APIC
extern int acpi_parse_ioapic (acpi_table_entry_header *header);
#endif /*CONFIG_X86_IO_APIC*/
#endif /*CONFIG_ACPI_BOOT*/
/*
* Intel MP BIOS table parsing routines:
*/
......@@ -122,13 +139,7 @@ static char __init *mpc_family(int family,int model)
return n;
}
#ifdef CONFIG_X86_IO_APIC
extern int have_acpi_tables; /* set by acpitable.c */
#else
#define have_acpi_tables (0)
#endif
/*
/*
* Have to match translation table entries to main table entries by counter
* hence the mpc_record variable .... can't see a less disgusting way of
* doing this ....
......@@ -427,10 +438,11 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
printk("APIC at: 0x%lX\n",mpc->mpc_lapic);
/* save the local APIC address, it might be non-default,
/*
* Save the local APIC address, it might be non-default,
* but only if we're not using the ACPI tables
*/
if (!have_acpi_tables)
if (!acpi_found_madt)
mp_lapic_addr = mpc->mpc_lapic;
if (clustered_apic_mode && mpc->mpc_oemptr) {
......@@ -451,7 +463,7 @@ static int __init smp_read_mpc(struct mp_config_table *mpc)
(struct mpc_config_processor *)mpt;
/* ACPI may already have provided this one for us */
if (!have_acpi_tables)
if (!acpi_found_madt)
MP_processor_info(m);
mpt += sizeof(*m);
count += sizeof(*m);
......@@ -665,7 +677,6 @@ static inline void __init construct_default_ISA_mptable(int mpc_default_type)
}
static struct intel_mp_floating *mpf_found;
extern void config_acpi_tables(void);
/*
* Scan the memory blocks for an SMP configuration block.
......@@ -674,16 +685,19 @@ void __init get_smp_config (void)
{
struct intel_mp_floating *mpf = mpf_found;
#ifdef CONFIG_X86_IO_APIC
#ifdef CONFIG_ACPI_BOOT
/*
* Check if the ACPI tables are provided. Use them only to get
* the processor information, mainly because it provides
* the info on the logical processor(s), rather than the physical
* processor(s) that are provided by the MPS. We attempt to
* check only if the user provided a commandline override
* Check if the MADT exists, and if so, use it to get processor
* information (ACPI_MADT_LAPIC). The MADT supports the concept
* of both logical (e.g. HT) and physical processor(s); where the
* MPS only supports physical.
*/
config_acpi_tables();
#endif
if (acpi_boot.madt) {
acpi_found_madt = acpi_table_parse(ACPI_APIC, acpi_parse_madt);
if (acpi_found_madt > 0)
acpi_table_parse_madt(ACPI_MADT_LAPIC, acpi_parse_lapic);
}
#endif /*CONFIG_ACPI_BOOT*/
printk("Intel MultiProcessor Specification v1.%d\n", mpf->mpf_specification);
if (mpf->mpf_feature2 & (1<<7)) {
......
......@@ -22,6 +22,7 @@
#define PCI_ASSIGN_ROMS 0x1000
#define PCI_BIOS_IRQ_SCAN 0x2000
#define PCI_ASSIGN_ALL_BUSSES 0x4000
#define PCI_NO_ACPI_ROUTING 0x8000
extern unsigned int pci_probe;
......@@ -65,6 +66,8 @@ struct irq_routing_table {
extern unsigned int pcibios_irq_mask;
extern int pci_use_acpi_routing;
void pcibios_irq_init(void);
void pcibios_fixup_irqs(void);
void pcibios_enable_irq(struct pci_dev *dev);
......@@ -12,7 +12,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/acpi.h>
#include <asm/io.h>
#include <asm/smp.h>
#include <asm/io_apic.h>
......@@ -22,6 +22,8 @@
#define PIRQ_SIGNATURE (('$' << 0) + ('P' << 8) + ('I' << 16) + ('R' << 24))
#define PIRQ_VERSION 0x0100
int pci_use_acpi_routing = 0;
static struct irq_routing_table *pirq_table;
/*
......@@ -512,6 +514,41 @@ static void __init pirq_find_router(void)
pirq_router_dev->slot_name);
}
static void pcibios_test_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
{
}
#ifdef CONFIG_ACPI_PCI
static int acpi_lookup_irq (
struct pci_dev *dev,
u8 pin,
int assign)
{
int result = 0;
int irq = 0;
/* TBD: Select IRQ from possible to improve routing performance. */
result = acpi_prt_get_irq(dev, pin, &irq);
if ((0 != result) || !irq) {
printk(KERN_ERR "PCI: Unable to resolve IRQ for device %s\n",
dev->slot_name);
return result;
}
printk(KERN_INFO "PCI: Found IRQ %d for device %s\n", irq,
dev->slot_name);
dev->irq = irq;
pirq_penalty[irq]++;
return 1;
}
#endif /* CONFIG_ACPI_PCI */
static struct irq_info *pirq_get_info(struct pci_dev *dev)
{
struct irq_routing_table *rt = pirq_table;
......@@ -524,38 +561,25 @@ static struct irq_info *pirq_get_info(struct pci_dev *dev)
return NULL;
}
static void pcibios_test_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
static int pirq_lookup_irq(struct pci_dev *dev, u8 pin, int assign)
{
}
static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
{
u8 pin;
struct irq_info *info;
int i, pirq, newirq;
int irq = 0;
u32 mask;
struct irq_router *r = pirq_router;
struct irq_info *info;
int newirq, pirq, i, irq = 0;
struct pci_dev *dev2;
char *msg = NULL;
u32 mask;
if (!pirq_table)
return 0;
/* Find IRQ routing entry */
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (!pin) {
DBG(" -> no interrupt pin\n");
return 0;
}
pin = pin - 1;
DBG("IRQ for %s:%d", dev->slot_name, pin);
info = pirq_get_info(dev);
if (!info) {
DBG(" -> not found in routing table\n");
return 0;
}
pirq = info->irq[pin].link;
mask = info->irq[pin].bitmap;
if (!pirq) {
......@@ -643,10 +667,42 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
return 1;
}
static int pcibios_lookup_irq(struct pci_dev *dev, int assign)
{
u8 pin;
/* Find IRQ routing entry */
pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
if (!pin) {
DBG("PCI: %s: no interrupt pin\n", dev->slot_name);
return 0;
}
pin -= 1;
#ifdef CONFIG_ACPI_PCI
if (pci_use_acpi_routing)
return acpi_lookup_irq(dev, pin, assign);
else
#endif
return pirq_lookup_irq(dev, pin, assign);
}
void __init pcibios_irq_init(void)
{
DBG("PCI: IRQ init\n");
#ifdef CONFIG_ACPI_PCI
if (acpi_prts.count && !(pci_probe & PCI_NO_ACPI_ROUTING)) {
printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n");
pci_use_acpi_routing = 1;
return;
}
if (!acpi_prts.count)
printk(KERN_INFO "PCI: Invalid acpi_prts [%d]\n", acpi_prts.count);
#endif
pirq_table = pirq_find_routing_table();
#ifdef CONFIG_PCI_BIOS
if (!pirq_table && (pci_probe & PCI_BIOS_IRQ_SCAN))
pirq_table = pcibios_get_irq_routing_table();
......
......@@ -1239,6 +1239,24 @@ void __devinit pcibios_fixup_bus(struct pci_bus *b)
}
struct pci_bus * __devinit pcibios_scan_root(int busnum)
{
struct list_head *list;
struct pci_bus *bus;
list_for_each(list, &pci_root_buses) {
bus = pci_bus_b(list);
if (bus->number == busnum) {
/* Already scanned */
return bus;
}
}
printk("PCI: Probing PCI hardware (bus %02x)\n", busnum);
return pci_scan_bus(busnum, pci_root_ops, NULL);
}
void __devinit pcibios_config_init(void)
{
/*
......@@ -1285,7 +1303,7 @@ void __init pcibios_init(void)
}
printk("PCI: Probing PCI hardware\n");
pci_root_bus = pci_scan_bus(0, pci_root_ops, NULL);
pci_root_bus = pcibios_scan_root(0);
if (clustered_apic_mode && (numnodes > 1)) {
for (quad = 1; quad < numnodes; ++quad) {
printk("Scanning PCI bus %d for quad %d\n",
......@@ -1296,7 +1314,10 @@ void __init pcibios_init(void)
}
pcibios_irq_init();
pcibios_fixup_peer_bridges();
if (!pci_use_acpi_routing)
pcibios_fixup_peer_bridges();
pcibios_fixup_irqs();
pcibios_resource_survey();
......@@ -1336,6 +1357,12 @@ char * __devinit pcibios_setup(char *str)
pci_probe = PCI_PROBE_CONF2 | PCI_NO_CHECKS;
return NULL;
}
#endif
#ifdef CONFIG_ACPI_PCI
else if (!strcmp(str, "noacpi")) {
pci_probe |= PCI_NO_ACPI_ROUTING;
return NULL;
}
#endif
else if (!strcmp(str, "rom")) {
pci_probe |= PCI_ASSIGN_ROMS;
......
......@@ -92,6 +92,7 @@
#include <linux/delay.h>
#include <linux/config.h>
#include <linux/init.h>
#include <linux/acpi.h>
#include <linux/apm_bios.h>
#ifdef CONFIG_BLK_DEV_RAM
#include <linux/blk.h>
......@@ -168,8 +169,6 @@ void __init visws_get_board_type_and_rev(void);
static int disable_x86_serial_nr __initdata = 1;
static int disable_x86_fxsr __initdata = 0;
int enable_acpi_smp_table;
/*
* This is set up by the setup-routine at boot-time
*/
......@@ -642,9 +641,6 @@ static void __init parse_mem_cmdline (char ** cmdline_p)
add_memory_region(start_at, mem_size, E820_RAM);
}
}
/* acpismp=force forces parsing and use of the ACPI SMP table */
if (c == ' ' && !memcmp(from, "acpismp=force", 13))
enable_acpi_smp_table = 1;
/*
* highmem=size forces highmem to be exactly 'size' bytes.
* This works even on boxes that have no highmem otherwise.
......@@ -869,7 +865,12 @@ void __init setup_arch(char **cmdline_p)
*/
reserve_bootmem(PAGE_SIZE, PAGE_SIZE);
#endif
#ifdef CONFIG_ACPI_SLEEP
/*
* Reserve low memory region for sleep support.
*/
acpi_reserve_bootmem();
#endif
#ifdef CONFIG_X86_LOCAL_APIC
/*
* Find and reserve possible boot-time SMP configuration:
......@@ -903,6 +904,15 @@ void __init setup_arch(char **cmdline_p)
smp_alloc_memory(); /* AP processor realmode stacks in low memory*/
#endif
paging_init();
#ifdef CONFIG_ACPI_BOOT
/*
* Initialize the ACPI boot-time table parser (gets the RSDP and SDT).
* Must do this after paging_init (due to reliance on fixmap, and thus
* the bootmem allocator) but before get_smp_config (to allow parsing
* of MADT).
*/
acpi_table_init(*cmdline_p);
#endif
#ifdef CONFIG_X86_LOCAL_APIC
/*
* get boot-time SMP configuration:
......
......@@ -19,10 +19,7 @@
# define DBG(x...)
#endif
static struct device device_root = {
bus_id: "root",
name: "System Root",
};
static struct device * device_root = NULL;
int (*platform_notify)(struct device * dev) = NULL;
int (*platform_notify_remove)(struct device * dev) = NULL;
......@@ -38,7 +35,10 @@ static spinlock_t device_lock;
*
* First, make sure that the device has a parent, create
* a directory for it, then add it to the parent's list of
* children.
* children. Note that the first device to be registered
* becomes the device_root, implying that the system root
* driver (e.g. ACPI, PnP BIOS, etc.) begins the device
* enumeration process.
*/
int device_register(struct device *dev)
{
......@@ -47,15 +47,28 @@ int device_register(struct device *dev)
if (!dev || !strlen(dev->bus_id))
return -EINVAL;
/* perform first-time initialization (system root device) */
if (!device_root) {
spin_lock_init(&device_lock);
error = init_driverfs_fs();
if (error) {
panic("DEV: could not initialise driverfs\n");
return error;
}
device_root = dev;
}
spin_lock(&device_lock);
INIT_LIST_HEAD(&dev->node);
INIT_LIST_HEAD(&dev->children);
spin_lock_init(&dev->lock);
atomic_set(&dev->refcount,2);
if (dev != &device_root) {
if (dev != device_root) {
if (!dev->parent)
dev->parent = &device_root;
dev->parent = device_root;
get_device(dev->parent);
list_add_tail(&dev->node,&dev->parent->children);
}
......@@ -120,28 +133,33 @@ void put_device(struct device * dev)
}
static int __init device_init_root(void)
{
return device_register(&device_root);
}
static int __init device_init(void)
{
int error = 0;
DBG("DEV: Initialising Device Tree\n");
device_root = kmalloc(sizeof(struct device),GFP_KERNEL);
if (!device_root)
return -ENOMEM;
memset(device_root,0,sizeof(struct device));
spin_lock_init(&device_lock);
if ((error = device_register(device_root)))
printk(KERN_ERR "%s: device root init failed!\n", __FUNCTION__);
error = init_driverfs_fs();
return error;
}
if (error) {
panic("DEV: could not initialise driverfs\n");
return error;
}
/**
* device_init - initialize the root device
*
* Ensures creation of the system root device (device_root)
* in the absence of a system root enumerator (e.g. ACPI,
* PnP BIOS, <insert non-IA paradigm here>, etc.).
*/
static int __init device_init(void)
{
if (!device_root)
return device_init_root();
if ((error = device_init_root()))
printk(KERN_ERR "%s: device root init failed!\n", __FUNCTION__);
return error;
return 0;
}
subsys_initcall(device_init);
......
......@@ -15,6 +15,7 @@
#include <linux/config.h>
#include <linux/kernel.h>
#include <asm/acpi.h>
#include <asm/apicdef.h>
#include <asm/page.h>
#ifdef CONFIG_HIGHMEM
......@@ -67,6 +68,10 @@ enum fixed_addresses {
#ifdef CONFIG_HIGHMEM
FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */
FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1,
#endif
#ifdef CONFIG_ACPI_BOOT
FIX_ACPI_BEGIN,
FIX_ACPI_END = FIX_ACPI_BEGIN + FIX_ACPI_PAGES - 1,
#endif
__end_of_permanent_fixed_addresses,
/* temporary boot-time mappings, used before ioremap() is functional */
......
......@@ -19,6 +19,11 @@ extern unsigned long pci_mem_start;
#define PCIBIOS_MIN_IO 0x1000
#define PCIBIOS_MIN_MEM (pci_mem_start)
void pcibios_config_init(void);
struct pci_bus * pcibios_scan_root(int bus);
extern int (*pci_config_read)(int seg, int bus, int dev, int fn, int reg, int len, u32 *value);
extern int (*pci_config_write)(int seg, int bus, int dev, int fn, int reg, int len, u32 value);
void pcibios_set_master(struct pci_dev *dev);
void pcibios_penalize_isa_irq(int irq);
struct irq_routing_table *pcibios_get_irq_routing_table(void);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment