Commit adb2705a authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/pci-2.6

parents f340c0d1 8644d2a4
...@@ -1030,6 +1030,10 @@ running once the system is up. ...@@ -1030,6 +1030,10 @@ running once the system is up.
irqmask=0xMMMM [IA-32] Set a bit mask of IRQs allowed to be assigned irqmask=0xMMMM [IA-32] Set a bit mask of IRQs allowed to be assigned
automatically to PCI devices. You can make the kernel automatically to PCI devices. You can make the kernel
exclude IRQs of your ISA cards this way. exclude IRQs of your ISA cards this way.
pirqaddr=0xAAAAA [IA-32] Specify the physical address
of the PIRQ table (normally generated
by the BIOS) if it is outside the
F0000h-100000h range.
lastbus=N [IA-32] Scan all buses till bus #N. Can be useful lastbus=N [IA-32] Scan all buses till bus #N. Can be useful
if the kernel is unable to find your secondary buses if the kernel is unable to find your secondary buses
and you want to tell it explicitly which ones they are. and you want to tell it explicitly which ones they are.
......
...@@ -159,9 +159,15 @@ char *__acpi_map_table(unsigned long phys, unsigned long size) ...@@ -159,9 +159,15 @@ char *__acpi_map_table(unsigned long phys, unsigned long size)
#endif #endif
#ifdef CONFIG_PCI_MMCONFIG #ifdef CONFIG_PCI_MMCONFIG
static int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size) /* The physical address of the MMCONFIG aperture. Set from ACPI tables. */
struct acpi_table_mcfg_config *pci_mmcfg_config;
int pci_mmcfg_config_num;
int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
{ {
struct acpi_table_mcfg *mcfg; struct acpi_table_mcfg *mcfg;
unsigned long i;
int config_size;
if (!phys_addr || !size) if (!phys_addr || !size)
return -EINVAL; return -EINVAL;
...@@ -172,18 +178,38 @@ static int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size) ...@@ -172,18 +178,38 @@ static int __init acpi_parse_mcfg(unsigned long phys_addr, unsigned long size)
return -ENODEV; return -ENODEV;
} }
if (mcfg->base_reserved) { /* how many config structures do we have */
printk(KERN_ERR PREFIX "MMCONFIG not in low 4GB of memory\n"); pci_mmcfg_config_num = 0;
i = size - sizeof(struct acpi_table_mcfg);
while (i >= sizeof(struct acpi_table_mcfg_config)) {
++pci_mmcfg_config_num;
i -= sizeof(struct acpi_table_mcfg_config);
};
if (pci_mmcfg_config_num == 0) {
printk(KERN_ERR PREFIX "MMCONFIG has no entries\n");
return -ENODEV; return -ENODEV;
} }
pci_mmcfg_base_addr = mcfg->base_address; config_size = pci_mmcfg_config_num * sizeof(*pci_mmcfg_config);
pci_mmcfg_config = kmalloc(config_size, GFP_KERNEL);
if (!pci_mmcfg_config) {
printk(KERN_WARNING PREFIX
"No memory for MCFG config tables\n");
return -ENOMEM;
}
memcpy(pci_mmcfg_config, &mcfg->config, config_size);
for (i = 0; i < pci_mmcfg_config_num; ++i) {
if (mcfg->config[i].base_reserved) {
printk(KERN_ERR PREFIX
"MMCONFIG not in low 4GB of memory\n");
return -ENODEV;
}
}
return 0; return 0;
} }
#else #endif /* CONFIG_PCI_MMCONFIG */
#define acpi_parse_mcfg NULL
#endif /* !CONFIG_PCI_MMCONFIG */
#ifdef CONFIG_X86_LOCAL_APIC #ifdef CONFIG_X86_LOCAL_APIC
static int __init static int __init
...@@ -507,6 +533,22 @@ acpi_unmap_lsapic(int cpu) ...@@ -507,6 +533,22 @@ acpi_unmap_lsapic(int cpu)
EXPORT_SYMBOL(acpi_unmap_lsapic); EXPORT_SYMBOL(acpi_unmap_lsapic);
#endif /* CONFIG_ACPI_HOTPLUG_CPU */ #endif /* CONFIG_ACPI_HOTPLUG_CPU */
int
acpi_register_ioapic(acpi_handle handle, u64 phys_addr, u32 gsi_base)
{
/* TBD */
return -EINVAL;
}
EXPORT_SYMBOL(acpi_register_ioapic);
int
acpi_unregister_ioapic(acpi_handle handle, u32 gsi_base)
{
/* TBD */
return -EINVAL;
}
EXPORT_SYMBOL(acpi_unregister_ioapic);
static unsigned long __init static unsigned long __init
acpi_scan_rsdp ( acpi_scan_rsdp (
unsigned long start, unsigned long start,
...@@ -1123,7 +1165,6 @@ int __init acpi_boot_init(void) ...@@ -1123,7 +1165,6 @@ int __init acpi_boot_init(void)
acpi_process_madt(); acpi_process_madt();
acpi_table_parse(ACPI_HPET, acpi_parse_hpet); acpi_table_parse(ACPI_HPET, acpi_parse_hpet);
acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
return 0; return 0;
} }
......
...@@ -25,7 +25,8 @@ unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 | ...@@ -25,7 +25,8 @@ unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2 |
int pci_routeirq; int pci_routeirq;
int pcibios_last_bus = -1; int pcibios_last_bus = -1;
struct pci_bus *pci_root_bus = NULL; unsigned long pirq_table_addr;
struct pci_bus *pci_root_bus;
struct pci_raw_ops *raw_pci_ops; struct pci_raw_ops *raw_pci_ops;
static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
...@@ -133,7 +134,7 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum) ...@@ -133,7 +134,7 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum)
printk("PCI: Probing PCI hardware (bus %02x)\n", busnum); printk("PCI: Probing PCI hardware (bus %02x)\n", busnum);
return pci_scan_bus(busnum, &pci_root_ops, NULL); return pci_scan_bus_parented(NULL, busnum, &pci_root_ops, NULL);
} }
extern u8 pci_cache_line_size; extern u8 pci_cache_line_size;
...@@ -188,6 +189,9 @@ char * __devinit pcibios_setup(char *str) ...@@ -188,6 +189,9 @@ char * __devinit pcibios_setup(char *str)
} else if (!strcmp(str, "biosirq")) { } else if (!strcmp(str, "biosirq")) {
pci_probe |= PCI_BIOS_IRQ_SCAN; pci_probe |= PCI_BIOS_IRQ_SCAN;
return NULL; return NULL;
} else if (!strncmp(str, "pirqaddr=", 9)) {
pirq_table_addr = simple_strtoul(str+9, NULL, 0);
return NULL;
} }
#endif #endif
#ifdef CONFIG_PCI_DIRECT #ifdef CONFIG_PCI_DIRECT
......
...@@ -57,6 +57,35 @@ struct irq_router_handler { ...@@ -57,6 +57,35 @@ struct irq_router_handler {
int (*pcibios_enable_irq)(struct pci_dev *dev) = NULL; int (*pcibios_enable_irq)(struct pci_dev *dev) = NULL;
/*
* Check passed address for the PCI IRQ Routing Table signature
* and perform checksum verification.
*/
static inline struct irq_routing_table * pirq_check_routing_table(u8 *addr)
{
struct irq_routing_table *rt;
int i;
u8 sum;
rt = (struct irq_routing_table *) addr;
if (rt->signature != PIRQ_SIGNATURE ||
rt->version != PIRQ_VERSION ||
rt->size % 16 ||
rt->size < sizeof(struct irq_routing_table))
return NULL;
sum = 0;
for (i=0; i < rt->size; i++)
sum += addr[i];
if (!sum) {
DBG("PCI: Interrupt Routing Table found at 0x%p\n", rt);
return rt;
}
return NULL;
}
/* /*
* Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table. * Search 0xf0000 -- 0xfffff for the PCI IRQ Routing Table.
*/ */
...@@ -65,23 +94,17 @@ static struct irq_routing_table * __init pirq_find_routing_table(void) ...@@ -65,23 +94,17 @@ static struct irq_routing_table * __init pirq_find_routing_table(void)
{ {
u8 *addr; u8 *addr;
struct irq_routing_table *rt; struct irq_routing_table *rt;
int i;
u8 sum;
if (pirq_table_addr) {
rt = pirq_check_routing_table((u8 *) __va(pirq_table_addr));
if (rt)
return rt;
printk(KERN_WARNING "PCI: PIRQ table NOT found at pirqaddr\n");
}
for(addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) { for(addr = (u8 *) __va(0xf0000); addr < (u8 *) __va(0x100000); addr += 16) {
rt = (struct irq_routing_table *) addr; rt = pirq_check_routing_table(addr);
if (rt->signature != PIRQ_SIGNATURE || if (rt)
rt->version != PIRQ_VERSION ||
rt->size % 16 ||
rt->size < sizeof(struct irq_routing_table))
continue;
sum = 0;
for(i=0; i<rt->size; i++)
sum += addr[i];
if (!sum) {
DBG("PCI: Interrupt Routing Table found at 0x%p\n", rt);
return rt; return rt;
}
} }
return NULL; return NULL;
} }
......
...@@ -45,6 +45,8 @@ static int __init pci_legacy_init(void) ...@@ -45,6 +45,8 @@ static int __init pci_legacy_init(void)
printk("PCI: Probing PCI hardware\n"); printk("PCI: Probing PCI hardware\n");
pci_root_bus = pcibios_scan_root(0); pci_root_bus = pcibios_scan_root(0);
if (pci_root_bus)
pci_bus_add_devices(pci_root_bus);
pcibios_fixup_peer_bridges(); pcibios_fixup_peer_bridges();
......
...@@ -11,11 +11,9 @@ ...@@ -11,11 +11,9 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/acpi.h>
#include "pci.h" #include "pci.h"
/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */
u32 pci_mmcfg_base_addr;
#define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG)) #define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG))
/* The base address of the last MMCONFIG device accessed */ /* The base address of the last MMCONFIG device accessed */
...@@ -24,10 +22,31 @@ static u32 mmcfg_last_accessed_device; ...@@ -24,10 +22,31 @@ static u32 mmcfg_last_accessed_device;
/* /*
* Functions for accessing PCI configuration space with MMCONFIG accesses * Functions for accessing PCI configuration space with MMCONFIG accesses
*/ */
static u32 get_base_addr(unsigned int seg, int bus)
{
int cfg_num = -1;
struct acpi_table_mcfg_config *cfg;
while (1) {
++cfg_num;
if (cfg_num >= pci_mmcfg_config_num) {
/* something bad is going on, no cfg table is found. */
/* so we fall back to the old way we used to do this */
/* and just rely on the first entry to be correct. */
return pci_mmcfg_config[0].base_address;
}
cfg = &pci_mmcfg_config[cfg_num];
if (cfg->pci_segment_group_number != seg)
continue;
if ((cfg->start_bus_number <= bus) &&
(cfg->end_bus_number >= bus))
return cfg->base_address;
}
}
static inline void pci_exp_set_dev_base(int bus, int devfn) static inline void pci_exp_set_dev_base(unsigned int seg, int bus, int devfn)
{ {
u32 dev_base = pci_mmcfg_base_addr | (bus << 20) | (devfn << 12); u32 dev_base = get_base_addr(seg, bus) | (bus << 20) | (devfn << 12);
if (dev_base != mmcfg_last_accessed_device) { if (dev_base != mmcfg_last_accessed_device) {
mmcfg_last_accessed_device = dev_base; mmcfg_last_accessed_device = dev_base;
set_fixmap_nocache(FIX_PCIE_MCFG, dev_base); set_fixmap_nocache(FIX_PCIE_MCFG, dev_base);
...@@ -44,7 +63,7 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus, ...@@ -44,7 +63,7 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
spin_lock_irqsave(&pci_config_lock, flags); spin_lock_irqsave(&pci_config_lock, flags);
pci_exp_set_dev_base(bus, devfn); pci_exp_set_dev_base(seg, bus, devfn);
switch (len) { switch (len) {
case 1: case 1:
...@@ -73,7 +92,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus, ...@@ -73,7 +92,7 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
spin_lock_irqsave(&pci_config_lock, flags); spin_lock_irqsave(&pci_config_lock, flags);
pci_exp_set_dev_base(bus, devfn); pci_exp_set_dev_base(seg, bus, devfn);
switch (len) { switch (len) {
case 1: case 1:
...@@ -101,7 +120,11 @@ static int __init pci_mmcfg_init(void) ...@@ -101,7 +120,11 @@ static int __init pci_mmcfg_init(void)
{ {
if ((pci_probe & PCI_PROBE_MMCONF) == 0) if ((pci_probe & PCI_PROBE_MMCONF) == 0)
goto out; goto out;
if (!pci_mmcfg_base_addr)
acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
if ((pci_mmcfg_config_num == 0) ||
(pci_mmcfg_config == NULL) ||
(pci_mmcfg_config[0].base_address == 0))
goto out; goto out;
/* Kludge for now. Don't use mmconfig on AMD systems because /* Kludge for now. Don't use mmconfig on AMD systems because
......
...@@ -115,6 +115,8 @@ static int __init pci_numa_init(void) ...@@ -115,6 +115,8 @@ static int __init pci_numa_init(void)
return 0; return 0;
pci_root_bus = pcibios_scan_root(0); pci_root_bus = pcibios_scan_root(0);
if (pci_root_bus)
pci_bus_add_devices(pci_root_bus);
if (num_online_nodes() > 1) if (num_online_nodes() > 1)
for_each_online_node(quad) { for_each_online_node(quad) {
if (quad == 0) if (quad == 0)
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#define PCI_ASSIGN_ALL_BUSSES 0x4000 #define PCI_ASSIGN_ALL_BUSSES 0x4000
extern unsigned int pci_probe; extern unsigned int pci_probe;
extern unsigned long pirq_table_addr;
/* pci-i386.c */ /* pci-i386.c */
......
...@@ -236,9 +236,7 @@ acpi_parse_iosapic (acpi_table_entry_header *header, const unsigned long end) ...@@ -236,9 +236,7 @@ acpi_parse_iosapic (acpi_table_entry_header *header, const unsigned long end)
if (BAD_MADT_ENTRY(iosapic, end)) if (BAD_MADT_ENTRY(iosapic, end))
return -EINVAL; return -EINVAL;
iosapic_init(iosapic->address, iosapic->global_irq_base); return iosapic_init(iosapic->address, iosapic->global_irq_base);
return 0;
} }
...@@ -772,7 +770,7 @@ EXPORT_SYMBOL(acpi_unmap_lsapic); ...@@ -772,7 +770,7 @@ EXPORT_SYMBOL(acpi_unmap_lsapic);
#ifdef CONFIG_ACPI_NUMA #ifdef CONFIG_ACPI_NUMA
acpi_status __init acpi_status __devinit
acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret) acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret)
{ {
struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL}; struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER, NULL};
...@@ -825,4 +823,28 @@ acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret) ...@@ -825,4 +823,28 @@ acpi_map_iosapic (acpi_handle handle, u32 depth, void *context, void **ret)
return AE_OK; return AE_OK;
} }
#endif /* CONFIG_NUMA */ #endif /* CONFIG_NUMA */
int
acpi_register_ioapic (acpi_handle handle, u64 phys_addr, u32 gsi_base)
{
int err;
if ((err = iosapic_init(phys_addr, gsi_base)))
return err;
#if CONFIG_ACPI_NUMA
acpi_map_iosapic(handle, 0, NULL, NULL);
#endif /* CONFIG_ACPI_NUMA */
return 0;
}
EXPORT_SYMBOL(acpi_register_ioapic);
int
acpi_unregister_ioapic (acpi_handle handle, u32 gsi_base)
{
return iosapic_remove(gsi_base);
}
EXPORT_SYMBOL(acpi_unregister_ioapic);
#endif /* CONFIG_ACPI_BOOT */ #endif /* CONFIG_ACPI_BOOT */
...@@ -129,14 +129,13 @@ static struct iosapic { ...@@ -129,14 +129,13 @@ static struct iosapic {
char __iomem *addr; /* base address of IOSAPIC */ char __iomem *addr; /* base address of IOSAPIC */
unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */ unsigned int gsi_base; /* first GSI assigned to this IOSAPIC */
unsigned short num_rte; /* number of RTE in this IOSAPIC */ unsigned short num_rte; /* number of RTE in this IOSAPIC */
int rtes_inuse; /* # of RTEs in use on this IOSAPIC */
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
unsigned short node; /* numa node association via pxm */ unsigned short node; /* numa node association via pxm */
#endif #endif
} iosapic_lists[NR_IOSAPICS]; } iosapic_lists[NR_IOSAPICS];
static int num_iosapic; static unsigned char pcat_compat __devinitdata; /* 8259 compatibility flag */
static unsigned char pcat_compat __initdata; /* 8259 compatibility flag */
static int iosapic_kmalloc_ok; static int iosapic_kmalloc_ok;
static LIST_HEAD(free_rte_list); static LIST_HEAD(free_rte_list);
...@@ -149,7 +148,7 @@ find_iosapic (unsigned int gsi) ...@@ -149,7 +148,7 @@ find_iosapic (unsigned int gsi)
{ {
int i; int i;
for (i = 0; i < num_iosapic; i++) { for (i = 0; i < NR_IOSAPICS; i++) {
if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte) if ((unsigned) (gsi - iosapic_lists[i].gsi_base) < iosapic_lists[i].num_rte)
return i; return i;
} }
...@@ -598,6 +597,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery, ...@@ -598,6 +597,7 @@ register_intr (unsigned int gsi, int vector, unsigned char delivery,
rte->refcnt++; rte->refcnt++;
list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes); list_add_tail(&rte->rte_list, &iosapic_intr_info[vector].rtes);
iosapic_intr_info[vector].count++; iosapic_intr_info[vector].count++;
iosapic_lists[index].rtes_inuse++;
} }
else if (vector_is_shared(vector)) { else if (vector_is_shared(vector)) {
struct iosapic_intr_info *info = &iosapic_intr_info[vector]; struct iosapic_intr_info *info = &iosapic_intr_info[vector];
...@@ -778,7 +778,7 @@ void ...@@ -778,7 +778,7 @@ void
iosapic_unregister_intr (unsigned int gsi) iosapic_unregister_intr (unsigned int gsi)
{ {
unsigned long flags; unsigned long flags;
int irq, vector; int irq, vector, index;
irq_desc_t *idesc; irq_desc_t *idesc;
u32 low32; u32 low32;
unsigned long trigger, polarity; unsigned long trigger, polarity;
...@@ -819,6 +819,9 @@ iosapic_unregister_intr (unsigned int gsi) ...@@ -819,6 +819,9 @@ iosapic_unregister_intr (unsigned int gsi)
list_del(&rte->rte_list); list_del(&rte->rte_list);
iosapic_intr_info[vector].count--; iosapic_intr_info[vector].count--;
iosapic_free_rte(rte); iosapic_free_rte(rte);
index = find_iosapic(gsi);
iosapic_lists[index].rtes_inuse--;
WARN_ON(iosapic_lists[index].rtes_inuse < 0);
trigger = iosapic_intr_info[vector].trigger; trigger = iosapic_intr_info[vector].trigger;
polarity = iosapic_intr_info[vector].polarity; polarity = iosapic_intr_info[vector].polarity;
...@@ -952,30 +955,86 @@ iosapic_system_init (int system_pcat_compat) ...@@ -952,30 +955,86 @@ iosapic_system_init (int system_pcat_compat)
} }
} }
void __init static inline int
iosapic_alloc (void)
{
int index;
for (index = 0; index < NR_IOSAPICS; index++)
if (!iosapic_lists[index].addr)
return index;
printk(KERN_WARNING "%s: failed to allocate iosapic\n", __FUNCTION__);
return -1;
}
static inline void
iosapic_free (int index)
{
memset(&iosapic_lists[index], 0, sizeof(iosapic_lists[0]));
}
static inline int
iosapic_check_gsi_range (unsigned int gsi_base, unsigned int ver)
{
int index;
unsigned int gsi_end, base, end;
/* check gsi range */
gsi_end = gsi_base + ((ver >> 16) & 0xff);
for (index = 0; index < NR_IOSAPICS; index++) {
if (!iosapic_lists[index].addr)
continue;
base = iosapic_lists[index].gsi_base;
end = base + iosapic_lists[index].num_rte - 1;
if (gsi_base < base && gsi_end < base)
continue;/* OK */
if (gsi_base > end && gsi_end > end)
continue; /* OK */
return -EBUSY;
}
return 0;
}
int __devinit
iosapic_init (unsigned long phys_addr, unsigned int gsi_base) iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
{ {
int num_rte; int num_rte, err, index;
unsigned int isa_irq, ver; unsigned int isa_irq, ver;
char __iomem *addr; char __iomem *addr;
unsigned long flags;
spin_lock_irqsave(&iosapic_lock, flags);
{
addr = ioremap(phys_addr, 0);
ver = iosapic_version(addr);
addr = ioremap(phys_addr, 0); if ((err = iosapic_check_gsi_range(gsi_base, ver))) {
ver = iosapic_version(addr); iounmap(addr);
spin_unlock_irqrestore(&iosapic_lock, flags);
return err;
}
/* /*
* The MAX_REDIR register holds the highest input pin * The MAX_REDIR register holds the highest input pin
* number (starting from 0). * number (starting from 0).
* We add 1 so that we can use it for number of pins (= RTEs) * We add 1 so that we can use it for number of pins (= RTEs)
*/ */
num_rte = ((ver >> 16) & 0xff) + 1; num_rte = ((ver >> 16) & 0xff) + 1;
iosapic_lists[num_iosapic].addr = addr; index = iosapic_alloc();
iosapic_lists[num_iosapic].gsi_base = gsi_base; iosapic_lists[index].addr = addr;
iosapic_lists[num_iosapic].num_rte = num_rte; iosapic_lists[index].gsi_base = gsi_base;
iosapic_lists[index].num_rte = num_rte;
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
iosapic_lists[num_iosapic].node = MAX_NUMNODES; iosapic_lists[index].node = MAX_NUMNODES;
#endif #endif
num_iosapic++; }
spin_unlock_irqrestore(&iosapic_lock, flags);
if ((gsi_base == 0) && pcat_compat) { if ((gsi_base == 0) && pcat_compat) {
/* /*
...@@ -986,10 +1045,43 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base) ...@@ -986,10 +1045,43 @@ iosapic_init (unsigned long phys_addr, unsigned int gsi_base)
for (isa_irq = 0; isa_irq < 16; ++isa_irq) for (isa_irq = 0; isa_irq < 16; ++isa_irq)
iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE); iosapic_override_isa_irq(isa_irq, isa_irq, IOSAPIC_POL_HIGH, IOSAPIC_EDGE);
} }
return 0;
}
#ifdef CONFIG_HOTPLUG
int
iosapic_remove (unsigned int gsi_base)
{
int index, err = 0;
unsigned long flags;
spin_lock_irqsave(&iosapic_lock, flags);
{
index = find_iosapic(gsi_base);
if (index < 0) {
printk(KERN_WARNING "%s: No IOSAPIC for GSI base %u\n",
__FUNCTION__, gsi_base);
goto out;
}
if (iosapic_lists[index].rtes_inuse) {
err = -EBUSY;
printk(KERN_WARNING "%s: IOSAPIC for GSI base %u is busy\n",
__FUNCTION__, gsi_base);
goto out;
}
iounmap(iosapic_lists[index].addr);
iosapic_free(index);
}
out:
spin_unlock_irqrestore(&iosapic_lock, flags);
return err;
} }
#endif /* CONFIG_HOTPLUG */
#ifdef CONFIG_NUMA #ifdef CONFIG_NUMA
void __init void __devinit
map_iosapic_to_node(unsigned int gsi_base, int node) map_iosapic_to_node(unsigned int gsi_base, int node)
{ {
int index; int index;
......
...@@ -312,7 +312,7 @@ pci_acpi_scan_root(struct acpi_device *device, int domain, int bus) ...@@ -312,7 +312,7 @@ pci_acpi_scan_root(struct acpi_device *device, int domain, int bus)
acpi_walk_resources(device->handle, METHOD_NAME__CRS, add_window, acpi_walk_resources(device->handle, METHOD_NAME__CRS, add_window,
&info); &info);
pbus = pci_scan_bus(bus, &pci_root_ops, controller); pbus = pci_scan_bus_parented(NULL, bus, &pci_root_ops, controller);
if (pbus) if (pbus)
pcibios_setup_root_windows(pbus, controller); pcibios_setup_root_windows(pbus, controller);
...@@ -373,6 +373,25 @@ void pcibios_bus_to_resource(struct pci_dev *dev, ...@@ -373,6 +373,25 @@ void pcibios_bus_to_resource(struct pci_dev *dev,
res->end = region->end + offset; res->end = region->end + offset;
} }
static int __devinit is_valid_resource(struct pci_dev *dev, int idx)
{
unsigned int i, type_mask = IORESOURCE_IO | IORESOURCE_MEM;
struct resource *devr = &dev->resource[idx];
if (!dev->bus)
return 0;
for (i=0; i<PCI_BUS_NUM_RESOURCES; i++) {
struct resource *busr = dev->bus->resource[i];
if (!busr || ((busr->flags ^ devr->flags) & type_mask))
continue;
if ((devr->start) && (devr->start >= busr->start) &&
(devr->end <= busr->end))
return 1;
}
return 0;
}
static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev) static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)
{ {
struct pci_bus_region region; struct pci_bus_region region;
...@@ -386,7 +405,8 @@ static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev) ...@@ -386,7 +405,8 @@ static void __devinit pcibios_fixup_device_resources(struct pci_dev *dev)
region.start = dev->resource[i].start; region.start = dev->resource[i].start;
region.end = dev->resource[i].end; region.end = dev->resource[i].end;
pcibios_bus_to_resource(dev, &dev->resource[i], &region); pcibios_bus_to_resource(dev, &dev->resource[i], &region);
pci_claim_resource(dev, i); if ((is_valid_resource(dev, i)))
pci_claim_resource(dev, i);
} }
} }
...@@ -398,6 +418,10 @@ pcibios_fixup_bus (struct pci_bus *b) ...@@ -398,6 +418,10 @@ pcibios_fixup_bus (struct pci_bus *b)
{ {
struct pci_dev *dev; struct pci_dev *dev;
if (b->self) {
pci_read_bridge_bases(b);
pcibios_fixup_device_resources(b->self);
}
list_for_each_entry(dev, &b->devices, bus_list) list_for_each_entry(dev, &b->devices, bus_list)
pcibios_fixup_device_resources(dev); pcibios_fixup_device_resources(dev);
...@@ -418,18 +442,24 @@ pcibios_enable_resources (struct pci_dev *dev, int mask) ...@@ -418,18 +442,24 @@ pcibios_enable_resources (struct pci_dev *dev, int mask)
u16 cmd, old_cmd; u16 cmd, old_cmd;
int idx; int idx;
struct resource *r; struct resource *r;
unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM;
if (!dev) if (!dev)
return -EINVAL; return -EINVAL;
pci_read_config_word(dev, PCI_COMMAND, &cmd); pci_read_config_word(dev, PCI_COMMAND, &cmd);
old_cmd = cmd; old_cmd = cmd;
for (idx=0; idx<6; idx++) { for (idx=0; idx<PCI_NUM_RESOURCES; idx++) {
/* Only set up the desired resources. */ /* Only set up the desired resources. */
if (!(mask & (1 << idx))) if (!(mask & (1 << idx)))
continue; continue;
r = &dev->resource[idx]; r = &dev->resource[idx];
if (!(r->flags & type_mask))
continue;
if ((idx == PCI_ROM_RESOURCE) &&
(!(r->flags & IORESOURCE_ROM_ENABLE)))
continue;
if (!r->start && r->end) { if (!r->start && r->end) {
printk(KERN_ERR printk(KERN_ERR
"PCI: Device %s not available because of resource collisions\n", "PCI: Device %s not available because of resource collisions\n",
...@@ -441,8 +471,6 @@ pcibios_enable_resources (struct pci_dev *dev, int mask) ...@@ -441,8 +471,6 @@ pcibios_enable_resources (struct pci_dev *dev, int mask)
if (r->flags & IORESOURCE_MEM) if (r->flags & IORESOURCE_MEM)
cmd |= PCI_COMMAND_MEMORY; cmd |= PCI_COMMAND_MEMORY;
} }
if (dev->resource[PCI_ROM_RESOURCE].start)
cmd |= PCI_COMMAND_MEMORY;
if (cmd != old_cmd) { if (cmd != old_cmd) {
printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd); printk("PCI: Enabling device %s (%04x -> %04x)\n", pci_name(dev), old_cmd, cmd);
pci_write_config_word(dev, PCI_COMMAND, cmd); pci_write_config_word(dev, PCI_COMMAND, cmd);
......
...@@ -1495,7 +1495,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, ...@@ -1495,7 +1495,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
*offset += hose->pci_mem_offset; *offset += hose->pci_mem_offset;
res_bit = IORESOURCE_MEM; res_bit = IORESOURCE_MEM;
} else { } else {
io_offset = (unsigned long)hose->io_base_virt; io_offset = hose->io_base_virt - ___IO_BASE;
*offset += io_offset; *offset += io_offset;
res_bit = IORESOURCE_IO; res_bit = IORESOURCE_IO;
} }
...@@ -1522,7 +1522,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, ...@@ -1522,7 +1522,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
/* found it! construct the final physical address */ /* found it! construct the final physical address */
if (mmap_state == pci_mmap_io) if (mmap_state == pci_mmap_io)
*offset += hose->io_base_phys - _IO_BASE; *offset += hose->io_base_phys - io_offset;
return rp; return rp;
} }
...@@ -1739,6 +1739,23 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn) ...@@ -1739,6 +1739,23 @@ long sys_pciconfig_iobase(long which, unsigned long bus, unsigned long devfn)
return result; return result;
} }
void pci_resource_to_user(const struct pci_dev *dev, int bar,
const struct resource *rsrc,
u64 *start, u64 *end)
{
struct pci_controller *hose = pci_bus_to_hose(dev->bus->number);
unsigned long offset = 0;
if (hose == NULL)
return;
if (rsrc->flags & IORESOURCE_IO)
offset = ___IO_BASE - hose->io_base_virt + hose->io_base_phys;
*start = rsrc->start + offset;
*end = rsrc->end + offset;
}
void __init void __init
pci_init_resource(struct resource *res, unsigned long start, unsigned long end, pci_init_resource(struct resource *res, unsigned long start, unsigned long end,
int flags, char *name) int flags, char *name)
......
...@@ -351,7 +351,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, ...@@ -351,7 +351,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
*offset += hose->pci_mem_offset; *offset += hose->pci_mem_offset;
res_bit = IORESOURCE_MEM; res_bit = IORESOURCE_MEM;
} else { } else {
io_offset = (unsigned long)hose->io_base_virt; io_offset = (unsigned long)hose->io_base_virt - pci_io_base;
*offset += io_offset; *offset += io_offset;
res_bit = IORESOURCE_IO; res_bit = IORESOURCE_IO;
} }
...@@ -378,7 +378,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev, ...@@ -378,7 +378,7 @@ static struct resource *__pci_mmap_make_offset(struct pci_dev *dev,
/* found it! construct the final physical address */ /* found it! construct the final physical address */
if (mmap_state == pci_mmap_io) if (mmap_state == pci_mmap_io)
*offset += hose->io_base_phys - io_offset; *offset += hose->io_base_phys - io_offset;
return rp; return rp;
} }
...@@ -944,4 +944,22 @@ int pci_read_irq_line(struct pci_dev *pci_dev) ...@@ -944,4 +944,22 @@ int pci_read_irq_line(struct pci_dev *pci_dev)
} }
EXPORT_SYMBOL(pci_read_irq_line); EXPORT_SYMBOL(pci_read_irq_line);
void pci_resource_to_user(const struct pci_dev *dev, int bar,
const struct resource *rsrc,
u64 *start, u64 *end)
{
struct pci_controller *hose = pci_bus_to_host(dev->bus);
unsigned long offset = 0;
if (hose == NULL)
return;
if (rsrc->flags & IORESOURCE_IO)
offset = pci_io_base - (unsigned long)hose->io_base_virt +
hose->io_base_phys;
*start = rsrc->start + offset;
*end = rsrc->end + offset;
}
#endif /* CONFIG_PPC_MULTIPLATFORM */ #endif /* CONFIG_PPC_MULTIPLATFORM */
...@@ -7,25 +7,50 @@ ...@@ -7,25 +7,50 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/acpi.h>
#include "pci.h" #include "pci.h"
#define MMCONFIG_APER_SIZE (256*1024*1024) #define MMCONFIG_APER_SIZE (256*1024*1024)
/* The physical address of the MMCONFIG aperture. Set from ACPI tables. */
u32 pci_mmcfg_base_addr;
/* Static virtual mapping of the MMCONFIG aperture */ /* Static virtual mapping of the MMCONFIG aperture */
char *pci_mmcfg_virt; struct mmcfg_virt {
struct acpi_table_mcfg_config *cfg;
char *virt;
};
static struct mmcfg_virt *pci_mmcfg_virt;
static inline char *pci_dev_base(unsigned int bus, unsigned int devfn) static char *get_virt(unsigned int seg, int bus)
{ {
return pci_mmcfg_virt + ((bus << 20) | (devfn << 12)); int cfg_num = -1;
struct acpi_table_mcfg_config *cfg;
while (1) {
++cfg_num;
if (cfg_num >= pci_mmcfg_config_num) {
/* something bad is going on, no cfg table is found. */
/* so we fall back to the old way we used to do this */
/* and just rely on the first entry to be correct. */
return pci_mmcfg_virt[0].virt;
}
cfg = pci_mmcfg_virt[cfg_num].cfg;
if (cfg->pci_segment_group_number != seg)
continue;
if ((cfg->start_bus_number <= bus) &&
(cfg->end_bus_number >= bus))
return pci_mmcfg_virt[cfg_num].virt;
}
}
static inline char *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
{
return get_virt(seg, bus) + ((bus << 20) | (devfn << 12));
} }
static int pci_mmcfg_read(unsigned int seg, unsigned int bus, static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 *value) unsigned int devfn, int reg, int len, u32 *value)
{ {
char *addr = pci_dev_base(bus, devfn); char *addr = pci_dev_base(seg, bus, devfn);
if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095))) if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095)))
return -EINVAL; return -EINVAL;
...@@ -48,7 +73,7 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus, ...@@ -48,7 +73,7 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
static int pci_mmcfg_write(unsigned int seg, unsigned int bus, static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
unsigned int devfn, int reg, int len, u32 value) unsigned int devfn, int reg, int len, u32 value)
{ {
char *addr = pci_dev_base(bus,devfn); char *addr = pci_dev_base(seg, bus, devfn);
if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
return -EINVAL; return -EINVAL;
...@@ -75,9 +100,15 @@ static struct pci_raw_ops pci_mmcfg = { ...@@ -75,9 +100,15 @@ static struct pci_raw_ops pci_mmcfg = {
static int __init pci_mmcfg_init(void) static int __init pci_mmcfg_init(void)
{ {
int i;
if ((pci_probe & PCI_PROBE_MMCONF) == 0) if ((pci_probe & PCI_PROBE_MMCONF) == 0)
return 0; return 0;
if (!pci_mmcfg_base_addr)
acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
if ((pci_mmcfg_config_num == 0) ||
(pci_mmcfg_config == NULL) ||
(pci_mmcfg_config[0].base_address == 0))
return 0; return 0;
/* Kludge for now. Don't use mmconfig on AMD systems because /* Kludge for now. Don't use mmconfig on AMD systems because
...@@ -88,13 +119,22 @@ static int __init pci_mmcfg_init(void) ...@@ -88,13 +119,22 @@ static int __init pci_mmcfg_init(void)
return 0; return 0;
/* RED-PEN i386 doesn't do _nocache right now */ /* RED-PEN i386 doesn't do _nocache right now */
pci_mmcfg_virt = ioremap_nocache(pci_mmcfg_base_addr, MMCONFIG_APER_SIZE); pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num, GFP_KERNEL);
if (!pci_mmcfg_virt) { if (pci_mmcfg_virt == NULL) {
printk("PCI: Cannot map mmconfig aperture\n"); printk("PCI: Can not allocate memory for mmconfig structures\n");
return 0; return 0;
} }
for (i = 0; i < pci_mmcfg_config_num; ++i) {
pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i];
pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].base_address, MMCONFIG_APER_SIZE);
if (!pci_mmcfg_virt[i].virt) {
printk("PCI: Cannot map mmconfig aperture for segment %d\n",
pci_mmcfg_config[i].pci_segment_group_number);
return 0;
}
printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_config[i].base_address);
}
printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_base_addr);
raw_pci_ops = &pci_mmcfg; raw_pci_ops = &pci_mmcfg;
pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
......
...@@ -153,7 +153,7 @@ container_device_add(struct acpi_device **device, acpi_handle handle) ...@@ -153,7 +153,7 @@ container_device_add(struct acpi_device **device, acpi_handle handle)
return_VALUE(-ENODEV); return_VALUE(-ENODEV);
} }
result = acpi_bus_scan(*device); result = acpi_bus_start(*device);
return_VALUE(result); return_VALUE(result);
} }
......
...@@ -61,15 +61,14 @@ acpi_pci_data_handler ( ...@@ -61,15 +61,14 @@ acpi_pci_data_handler (
/** /**
* acpi_os_get_pci_id * acpi_get_pci_id
* ------------------ * ------------------
* This function is used by the ACPI Interpreter (a.k.a. Core Subsystem) * This function is used by the ACPI Interpreter (a.k.a. Core Subsystem)
* to resolve PCI information for ACPI-PCI devices defined in the namespace. * to resolve PCI information for ACPI-PCI devices defined in the namespace.
* This typically occurs when resolving PCI operation region information. * This typically occurs when resolving PCI operation region information.
*/ */
#ifdef ACPI_FUTURE_USAGE
acpi_status acpi_status
acpi_os_get_pci_id ( acpi_get_pci_id (
acpi_handle handle, acpi_handle handle,
struct acpi_pci_id *id) struct acpi_pci_id *id)
{ {
...@@ -78,7 +77,7 @@ acpi_os_get_pci_id ( ...@@ -78,7 +77,7 @@ acpi_os_get_pci_id (
struct acpi_device *device = NULL; struct acpi_device *device = NULL;
struct acpi_pci_data *data = NULL; struct acpi_pci_data *data = NULL;
ACPI_FUNCTION_TRACE("acpi_os_get_pci_id"); ACPI_FUNCTION_TRACE("acpi_get_pci_id");
if (!id) if (!id)
return_ACPI_STATUS(AE_BAD_PARAMETER); return_ACPI_STATUS(AE_BAD_PARAMETER);
...@@ -92,7 +91,7 @@ acpi_os_get_pci_id ( ...@@ -92,7 +91,7 @@ acpi_os_get_pci_id (
} }
status = acpi_get_data(handle, acpi_pci_data_handler, (void**) &data); status = acpi_get_data(handle, acpi_pci_data_handler, (void**) &data);
if (ACPI_FAILURE(status) || !data || !data->dev) { if (ACPI_FAILURE(status) || !data) {
ACPI_DEBUG_PRINT((ACPI_DB_ERROR, ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
"Invalid ACPI-PCI context for device %s\n", "Invalid ACPI-PCI context for device %s\n",
acpi_device_bid(device))); acpi_device_bid(device)));
...@@ -115,7 +114,7 @@ acpi_os_get_pci_id ( ...@@ -115,7 +114,7 @@ acpi_os_get_pci_id (
return_ACPI_STATUS(AE_OK); return_ACPI_STATUS(AE_OK);
} }
#endif /* ACPI_FUTURE_USAGE */ EXPORT_SYMBOL(acpi_get_pci_id);
int int
...@@ -129,6 +128,8 @@ acpi_pci_bind ( ...@@ -129,6 +128,8 @@ acpi_pci_bind (
char *pathname = NULL; char *pathname = NULL;
struct acpi_buffer buffer = {0, NULL}; struct acpi_buffer buffer = {0, NULL};
acpi_handle handle = NULL; acpi_handle handle = NULL;
struct pci_dev *dev;
struct pci_bus *bus;
ACPI_FUNCTION_TRACE("acpi_pci_bind"); ACPI_FUNCTION_TRACE("acpi_pci_bind");
...@@ -193,8 +194,20 @@ acpi_pci_bind ( ...@@ -193,8 +194,20 @@ acpi_pci_bind (
* Locate matching device in PCI namespace. If it doesn't exist * Locate matching device in PCI namespace. If it doesn't exist
* this typically means that the device isn't currently inserted * this typically means that the device isn't currently inserted
* (e.g. docking station, port replicator, etc.). * (e.g. docking station, port replicator, etc.).
* We cannot simply search the global pci device list, since
* PCI devices are added to the global pci list when the root
* bridge start ops are run, which may not have happened yet.
*/ */
data->dev = pci_find_slot(data->id.bus, PCI_DEVFN(data->id.device, data->id.function)); bus = pci_find_bus(data->id.segment, data->id.bus);
if (bus) {
list_for_each_entry(dev, &bus->devices, bus_list) {
if (dev->devfn == PCI_DEVFN(data->id.device,
data->id.function)) {
data->dev = dev;
break;
}
}
}
if (!data->dev) { if (!data->dev) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Device %02x:%02x:%02x.%02x not present in PCI namespace\n", "Device %02x:%02x:%02x.%02x not present in PCI namespace\n",
......
...@@ -46,6 +46,7 @@ ACPI_MODULE_NAME ("pci_root") ...@@ -46,6 +46,7 @@ ACPI_MODULE_NAME ("pci_root")
static int acpi_pci_root_add (struct acpi_device *device); static int acpi_pci_root_add (struct acpi_device *device);
static int acpi_pci_root_remove (struct acpi_device *device, int type); static int acpi_pci_root_remove (struct acpi_device *device, int type);
static int acpi_pci_root_start (struct acpi_device *device);
static struct acpi_driver acpi_pci_root_driver = { static struct acpi_driver acpi_pci_root_driver = {
.name = ACPI_PCI_ROOT_DRIVER_NAME, .name = ACPI_PCI_ROOT_DRIVER_NAME,
...@@ -54,6 +55,7 @@ static struct acpi_driver acpi_pci_root_driver = { ...@@ -54,6 +55,7 @@ static struct acpi_driver acpi_pci_root_driver = {
.ops = { .ops = {
.add = acpi_pci_root_add, .add = acpi_pci_root_add,
.remove = acpi_pci_root_remove, .remove = acpi_pci_root_remove,
.start = acpi_pci_root_start,
}, },
}; };
...@@ -169,6 +171,7 @@ acpi_pci_root_add ( ...@@ -169,6 +171,7 @@ acpi_pci_root_add (
if (!root) if (!root)
return_VALUE(-ENOMEM); return_VALUE(-ENOMEM);
memset(root, 0, sizeof(struct acpi_pci_root)); memset(root, 0, sizeof(struct acpi_pci_root));
INIT_LIST_HEAD(&root->node);
root->handle = device->handle; root->handle = device->handle;
strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME); strcpy(acpi_device_name(device), ACPI_PCI_ROOT_DEVICE_NAME);
...@@ -298,12 +301,31 @@ acpi_pci_root_add ( ...@@ -298,12 +301,31 @@ acpi_pci_root_add (
root->id.bus); root->id.bus);
end: end:
if (result) if (result) {
if (!list_empty(&root->node))
list_del(&root->node);
kfree(root); kfree(root);
}
return_VALUE(result); return_VALUE(result);
} }
static int
acpi_pci_root_start (
struct acpi_device *device)
{
struct acpi_pci_root *root;
ACPI_FUNCTION_TRACE("acpi_pci_root_start");
list_for_each_entry(root, &acpi_pci_roots, node) {
if (root->handle == device->handle) {
pci_bus_add_devices(root->bus);
return_VALUE(0);
}
}
return_VALUE(-ENODEV);
}
static int static int
acpi_pci_root_remove ( acpi_pci_root_remove (
......
...@@ -723,7 +723,7 @@ int acpi_processor_device_add( ...@@ -723,7 +723,7 @@ int acpi_processor_device_add(
return_VALUE(-ENODEV); return_VALUE(-ENODEV);
} }
acpi_bus_scan(*device); acpi_bus_start(*device);
pr = acpi_driver_data(*device); pr = acpi_driver_data(*device);
if (!pr) if (!pr)
......
...@@ -553,20 +553,29 @@ acpi_bus_driver_init ( ...@@ -553,20 +553,29 @@ acpi_bus_driver_init (
* upon possible configuration and currently allocated resources. * upon possible configuration and currently allocated resources.
*/ */
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n"));
return_VALUE(0);
}
int
acpi_start_single_object (
struct acpi_device *device)
{
int result = 0;
struct acpi_driver *driver;
ACPI_FUNCTION_TRACE("acpi_start_single_object");
if (!(driver = device->driver))
return_VALUE(0);
if (driver->ops.start) { if (driver->ops.start) {
result = driver->ops.start(device); result = driver->ops.start(device);
if (result && driver->ops.remove) if (result && driver->ops.remove)
driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL); driver->ops.remove(device, ACPI_BUS_REMOVAL_NORMAL);
return_VALUE(result);
} }
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Driver successfully bound to device\n")); return_VALUE(result);
if (driver->ops.scan) {
driver->ops.scan(device);
}
return_VALUE(0);
} }
static int acpi_driver_attach(struct acpi_driver * drv) static int acpi_driver_attach(struct acpi_driver * drv)
...@@ -586,6 +595,7 @@ static int acpi_driver_attach(struct acpi_driver * drv) ...@@ -586,6 +595,7 @@ static int acpi_driver_attach(struct acpi_driver * drv)
if (!acpi_bus_match(dev, drv)) { if (!acpi_bus_match(dev, drv)) {
if (!acpi_bus_driver_init(dev, drv)) { if (!acpi_bus_driver_init(dev, drv)) {
acpi_start_single_object(dev);
atomic_inc(&drv->references); atomic_inc(&drv->references);
count++; count++;
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n", ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found driver [%s] for device [%s]\n",
...@@ -1009,8 +1019,8 @@ acpi_bus_remove ( ...@@ -1009,8 +1019,8 @@ acpi_bus_remove (
} }
int static int
acpi_bus_add ( acpi_add_single_object (
struct acpi_device **child, struct acpi_device **child,
struct acpi_device *parent, struct acpi_device *parent,
acpi_handle handle, acpi_handle handle,
...@@ -1019,7 +1029,7 @@ acpi_bus_add ( ...@@ -1019,7 +1029,7 @@ acpi_bus_add (
int result = 0; int result = 0;
struct acpi_device *device = NULL; struct acpi_device *device = NULL;
ACPI_FUNCTION_TRACE("acpi_bus_add"); ACPI_FUNCTION_TRACE("acpi_add_single_object");
if (!child) if (!child)
return_VALUE(-EINVAL); return_VALUE(-EINVAL);
...@@ -1140,7 +1150,7 @@ acpi_bus_add ( ...@@ -1140,7 +1150,7 @@ acpi_bus_add (
* *
* TBD: Assumes LDM provides driver hot-plug capability. * TBD: Assumes LDM provides driver hot-plug capability.
*/ */
acpi_bus_find_driver(device); result = acpi_bus_find_driver(device);
end: end:
if (!result) if (!result)
...@@ -1153,10 +1163,10 @@ acpi_bus_add ( ...@@ -1153,10 +1163,10 @@ acpi_bus_add (
return_VALUE(result); return_VALUE(result);
} }
EXPORT_SYMBOL(acpi_bus_add);
int acpi_bus_scan (struct acpi_device *start) static int acpi_bus_scan (struct acpi_device *start,
struct acpi_bus_ops *ops)
{ {
acpi_status status = AE_OK; acpi_status status = AE_OK;
struct acpi_device *parent = NULL; struct acpi_device *parent = NULL;
...@@ -1229,9 +1239,20 @@ int acpi_bus_scan (struct acpi_device *start) ...@@ -1229,9 +1239,20 @@ int acpi_bus_scan (struct acpi_device *start)
continue; continue;
} }
status = acpi_bus_add(&child, parent, chandle, type); if (ops->acpi_op_add)
if (ACPI_FAILURE(status)) status = acpi_add_single_object(&child, parent,
continue; chandle, type);
else
status = acpi_bus_get_device(chandle, &child);
if (ACPI_FAILURE(status))
continue;
if (ops->acpi_op_start) {
status = acpi_start_single_object(child);
if (ACPI_FAILURE(status))
continue;
}
/* /*
* If the device is present, enabled, and functioning then * If the device is present, enabled, and functioning then
...@@ -1257,8 +1278,50 @@ int acpi_bus_scan (struct acpi_device *start) ...@@ -1257,8 +1278,50 @@ int acpi_bus_scan (struct acpi_device *start)
return_VALUE(0); return_VALUE(0);
} }
EXPORT_SYMBOL(acpi_bus_scan);
int
acpi_bus_add (
struct acpi_device **child,
struct acpi_device *parent,
acpi_handle handle,
int type)
{
int result;
struct acpi_bus_ops ops;
ACPI_FUNCTION_TRACE("acpi_bus_add");
result = acpi_add_single_object(child, parent, handle, type);
if (!result) {
memset(&ops, 0, sizeof(ops));
ops.acpi_op_add = 1;
result = acpi_bus_scan(*child, &ops);
}
return_VALUE(result);
}
EXPORT_SYMBOL(acpi_bus_add);
int
acpi_bus_start (
struct acpi_device *device)
{
int result;
struct acpi_bus_ops ops;
ACPI_FUNCTION_TRACE("acpi_bus_start");
if (!device)
return_VALUE(-EINVAL);
result = acpi_start_single_object(device);
if (!result) {
memset(&ops, 0, sizeof(ops));
ops.acpi_op_start = 1;
result = acpi_bus_scan(device, &ops);
}
return_VALUE(result);
}
EXPORT_SYMBOL(acpi_bus_start);
static int static int
acpi_bus_trim(struct acpi_device *start, acpi_bus_trim(struct acpi_device *start,
...@@ -1331,13 +1394,19 @@ acpi_bus_scan_fixed ( ...@@ -1331,13 +1394,19 @@ acpi_bus_scan_fixed (
/* /*
* Enumerate all fixed-feature devices. * Enumerate all fixed-feature devices.
*/ */
if (acpi_fadt.pwr_button == 0) if (acpi_fadt.pwr_button == 0) {
result = acpi_bus_add(&device, acpi_root, result = acpi_add_single_object(&device, acpi_root,
NULL, ACPI_BUS_TYPE_POWER_BUTTON); NULL, ACPI_BUS_TYPE_POWER_BUTTON);
if (!result)
result = acpi_start_single_object(device);
}
if (acpi_fadt.sleep_button == 0) if (acpi_fadt.sleep_button == 0) {
result = acpi_bus_add(&device, acpi_root, result = acpi_add_single_object(&device, acpi_root,
NULL, ACPI_BUS_TYPE_SLEEP_BUTTON); NULL, ACPI_BUS_TYPE_SLEEP_BUTTON);
if (!result)
result = acpi_start_single_object(device);
}
return_VALUE(result); return_VALUE(result);
} }
...@@ -1346,6 +1415,7 @@ acpi_bus_scan_fixed ( ...@@ -1346,6 +1415,7 @@ acpi_bus_scan_fixed (
static int __init acpi_scan_init(void) static int __init acpi_scan_init(void)
{ {
int result; int result;
struct acpi_bus_ops ops;
ACPI_FUNCTION_TRACE("acpi_scan_init"); ACPI_FUNCTION_TRACE("acpi_scan_init");
...@@ -1357,17 +1427,23 @@ static int __init acpi_scan_init(void) ...@@ -1357,17 +1427,23 @@ static int __init acpi_scan_init(void)
/* /*
* Create the root device in the bus's device tree * Create the root device in the bus's device tree
*/ */
result = acpi_bus_add(&acpi_root, NULL, ACPI_ROOT_OBJECT, result = acpi_add_single_object(&acpi_root, NULL, ACPI_ROOT_OBJECT,
ACPI_BUS_TYPE_SYSTEM); ACPI_BUS_TYPE_SYSTEM);
if (result) if (result)
goto Done; goto Done;
result = acpi_start_single_object(acpi_root);
/* /*
* Enumerate devices in the ACPI namespace. * Enumerate devices in the ACPI namespace.
*/ */
result = acpi_bus_scan_fixed(acpi_root); result = acpi_bus_scan_fixed(acpi_root);
if (!result) if (!result) {
result = acpi_bus_scan(acpi_root); memset(&ops, 0, sizeof(ops));
ops.acpi_op_add = 1;
ops.acpi_op_start = 1;
result = acpi_bus_scan(acpi_root, &ops);
}
if (result) if (result)
acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL); acpi_device_unregister(acpi_root, ACPI_BUS_REMOVAL_NORMAL);
......
...@@ -451,7 +451,7 @@ static int __init moxa_init(void) ...@@ -451,7 +451,7 @@ static int __init moxa_init(void)
int n = (sizeof(moxa_pcibrds) / sizeof(moxa_pcibrds[0])) - 1; int n = (sizeof(moxa_pcibrds) / sizeof(moxa_pcibrds[0])) - 1;
i = 0; i = 0;
while (i < n) { while (i < n) {
while ((p = pci_find_device(moxa_pcibrds[i].vendor, moxa_pcibrds[i].device, p))!=NULL) while ((p = pci_get_device(moxa_pcibrds[i].vendor, moxa_pcibrds[i].device, p))!=NULL)
{ {
if (pci_enable_device(p)) if (pci_enable_device(p))
continue; continue;
......
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