summaryrefslogtreecommitdiffstats
path: root/arch/x86/pci
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2008-08-25 11:10:42 +0200
committerIngo Molnar <mingo@elte.hu>2008-08-25 11:10:42 +0200
commitea1c9de45ecb162841c9b4e0fa303a245d59b1c8 (patch)
tree72ef1624d8a4c581ad94a84f38f941682562030b /arch/x86/pci
parentarch/x86/kernel/apm_32.c: remove duplicated #include (diff)
parentx86: fix HPET regression in 2.6.26 versus 2.6.25, check hpet against BAR, v3 (diff)
downloadlinux-ea1c9de45ecb162841c9b4e0fa303a245d59b1c8.tar.xz
linux-ea1c9de45ecb162841c9b4e0fa303a245d59b1c8.zip
Merge branch 'x86/urgent' into x86/cleanups
Diffstat (limited to 'arch/x86/pci')
-rw-r--r--arch/x86/pci/amd_bus.c52
-rw-r--r--arch/x86/pci/i386.c78
2 files changed, 124 insertions, 6 deletions
diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c
index dbf532369711..6a0fca78c362 100644
--- a/arch/x86/pci/amd_bus.c
+++ b/arch/x86/pci/amd_bus.c
@@ -1,6 +1,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/topology.h>
+#include <linux/cpu.h>
#include "pci.h"
#ifdef CONFIG_X86_64
@@ -555,15 +556,17 @@ static int __init early_fill_mp_bus_info(void)
return 0;
}
-postcore_initcall(early_fill_mp_bus_info);
+#else /* !CONFIG_X86_64 */
-#endif
+static int __init early_fill_mp_bus_info(void) { return 0; }
+
+#endif /* !CONFIG_X86_64 */
/* common 32/64 bit code */
#define ENABLE_CF8_EXT_CFG (1ULL << 46)
-static void enable_pci_io_ecs_per_cpu(void *unused)
+static void enable_pci_io_ecs(void *unused)
{
u64 reg;
rdmsrl(MSR_AMD64_NB_CFG, reg);
@@ -573,14 +576,51 @@ static void enable_pci_io_ecs_per_cpu(void *unused)
}
}
-static int __init enable_pci_io_ecs(void)
+static int __cpuinit amd_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
{
+ int cpu = (long)hcpu;
+ switch(action) {
+ case CPU_ONLINE:
+ case CPU_ONLINE_FROZEN:
+ smp_call_function_single(cpu, enable_pci_io_ecs, NULL, 0);
+ break;
+ default:
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block __cpuinitdata amd_cpu_notifier = {
+ .notifier_call = amd_cpu_notify,
+};
+
+static int __init pci_io_ecs_init(void)
+{
+ int cpu;
+
/* assume all cpus from fam10h have IO ECS */
if (boot_cpu_data.x86 < 0x10)
return 0;
- on_each_cpu(enable_pci_io_ecs_per_cpu, NULL, 1);
+
+ register_cpu_notifier(&amd_cpu_notifier);
+ for_each_online_cpu(cpu)
+ amd_cpu_notify(&amd_cpu_notifier, (unsigned long)CPU_ONLINE,
+ (void *)(long)cpu);
pci_probe |= PCI_HAS_IO_ECS;
+
+ return 0;
+}
+
+static int __init amd_postcore_init(void)
+{
+ if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
+ return 0;
+
+ early_fill_mp_bus_info();
+ pci_io_ecs_init();
+
return 0;
}
-postcore_initcall(enable_pci_io_ecs);
+postcore_initcall(amd_postcore_init);
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index 5807d1bc73f7..d765da913842 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -31,8 +31,11 @@
#include <linux/ioport.h>
#include <linux/errno.h>
#include <linux/bootmem.h>
+#include <linux/acpi.h>
#include <asm/pat.h>
+#include <asm/hpet.h>
+#include <asm/io_apic.h>
#include "pci.h"
@@ -77,6 +80,77 @@ pcibios_align_resource(void *data, struct resource *res,
}
EXPORT_SYMBOL(pcibios_align_resource);
+static int check_res_with_valid(struct pci_dev *dev, struct resource *res)
+{
+ unsigned long base;
+ unsigned long size;
+ int i;
+
+ base = res->start;
+ size = (res->start == 0 && res->end == res->start) ? 0 :
+ (res->end - res->start + 1);
+
+ if (!base || !size)
+ return 0;
+
+#ifdef CONFIG_HPET_TIMER
+ /* for hpet */
+ if (base == hpet_address && (res->flags & IORESOURCE_MEM)) {
+ dev_info(&dev->dev, "BAR has HPET at %08lx-%08lx\n",
+ base, base + size - 1);
+ return 1;
+ }
+#endif
+
+#ifdef CONFIG_X86_IO_APIC
+ for (i = 0; i < nr_ioapics; i++) {
+ unsigned long ioapic_phys = mp_ioapics[i].mp_apicaddr;
+
+ if (base == ioapic_phys && (res->flags & IORESOURCE_MEM)) {
+ dev_info(&dev->dev, "BAR has ioapic at %08lx-%08lx\n",
+ base, base + size - 1);
+ return 1;
+ }
+ }
+#endif
+
+#ifdef CONFIG_PCI_MMCONFIG
+ for (i = 0; i < pci_mmcfg_config_num; i++) {
+ unsigned long addr;
+
+ addr = pci_mmcfg_config[i].address;
+ if (base == addr && (res->flags & IORESOURCE_MEM)) {
+ dev_info(&dev->dev, "BAR has MMCONFIG at %08lx-%08lx\n",
+ base, base + size - 1);
+ return 1;
+ }
+ }
+#endif
+
+ return 0;
+}
+
+static int check_platform(struct pci_dev *dev, struct resource *res)
+{
+ struct resource *root = NULL;
+
+ /*
+ * forcibly insert it into the
+ * resource tree
+ */
+ if (res->flags & IORESOURCE_MEM)
+ root = &iomem_resource;
+ else if (res->flags & IORESOURCE_IO)
+ root = &ioport_resource;
+
+ if (root && check_res_with_valid(dev, res)) {
+ insert_resource(root, res);
+
+ return 1;
+ }
+
+ return 0;
+}
/*
* Handle resources of PCI devices. If the world were perfect, we could
* just allocate all the resource regions and do nothing more. It isn't.
@@ -128,6 +202,8 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list)
pr = pci_find_parent_resource(dev, r);
if (!r->start || !pr ||
request_resource(pr, r) < 0) {
+ if (check_platform(dev, r))
+ continue;
dev_err(&dev->dev, "BAR %d: can't "
"allocate resource\n", idx);
/*
@@ -171,6 +247,8 @@ static void __init pcibios_allocate_resources(int pass)
r->flags, disabled, pass);
pr = pci_find_parent_resource(dev, r);
if (!pr || request_resource(pr, r) < 0) {
+ if (check_platform(dev, r))
+ continue;
dev_err(&dev->dev, "BAR %d: can't "
"allocate resource\n", idx);
/* We'll assign a new address later */