PCI x86: always use conf1 to access config space below 256 bytes
From: Matthew Wilcox
Date: Mon Jan 28 2008 - 21:57:59 EST
PCI x86: always use conf1 to access config space below 256 bytes
Thanks to Loic Prylli <loic@xxxxxxxx>, who originally proposed
this idea.
Always using legacy configuration mechanism for the legacy config space
and extended mechanism (mmconf) for the extended config space is
a simple and very logical approach. It's supposed to resolve all
known mmconf problems. It still allows per-device quirks (tweaking
dev->cfg_size). It also allows to get rid of mmconf fallback code.
Signed-off-by: Ivan Kokshaysky <ink@xxxxxxxxxxxxxxxxxxxx>
Signed-off-by: Matthew Wilcox <willy@xxxxxxxxxxxxxxx>
---
arch/x86/pci/mmconfig-shared.c | 35 -----------------------------------
arch/x86/pci/mmconfig_32.c | 22 +++++++++-------------
arch/x86/pci/mmconfig_64.c | 22 ++++++++++------------
arch/x86/pci/pci.h | 7 -------
4 files changed, 19 insertions(+), 67 deletions(-)
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
index 4df637e..6b521d3 100644
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -22,42 +22,9 @@
#define MMCONFIG_APER_MIN (2 * 1024*1024)
#define MMCONFIG_APER_MAX (256 * 1024*1024)
-DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS);
-
/* Indicate if the mmcfg resources have been placed into the resource table. */
static int __initdata pci_mmcfg_resources_inserted;
-/* K8 systems have some devices (typically in the builtin northbridge)
- that are only accessible using type1
- Normally this can be expressed in the MCFG by not listing them
- and assigning suitable _SEGs, but this isn't implemented in some BIOS.
- Instead try to discover all devices on bus 0 that are unreachable using MM
- and fallback for them. */
-static void __init unreachable_devices(void)
-{
- int i, bus;
- /* Use the max bus number from ACPI here? */
- for (bus = 0; bus < PCI_MMCFG_MAX_CHECK_BUS; bus++) {
- for (i = 0; i < 32; i++) {
- unsigned int devfn = PCI_DEVFN(i, 0);
- u32 val1, val2;
-
- pci_conf1_read(0, bus, devfn, 0, 4, &val1);
- if (val1 == 0xffffffff)
- continue;
-
- if (pci_mmcfg_arch_reachable(0, bus, devfn)) {
- raw_pci_ops->read(0, bus, devfn, 0, 4, &val2);
- if (val1 == val2)
- continue;
- }
- set_bit(i + 32 * bus, pci_mmcfg_fallback_slots);
- printk(KERN_NOTICE "PCI: No mmconfig possible on device"
- " %02x:%02x\n", bus, i);
- }
- }
-}
-
static const char __init *pci_mmcfg_e7520(void)
{
u32 win;
@@ -270,8 +237,6 @@ void __init pci_mmcfg_init(int type)
return;
if (pci_mmcfg_arch_init()) {
- if (type == 1)
- unreachable_devices();
if (known_bridge)
pci_mmcfg_insert_resources(IORESOURCE_BUSY);
pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
diff --git a/arch/x86/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c
index 1bf5816..7b75e65 100644
--- a/arch/x86/pci/mmconfig_32.c
+++ b/arch/x86/pci/mmconfig_32.c
@@ -30,10 +30,6 @@ static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
struct acpi_mcfg_allocation *cfg;
int cfg_num;
- if (seg == 0 && bus < PCI_MMCFG_MAX_CHECK_BUS &&
- test_bit(PCI_SLOT(devfn) + 32*bus, pci_mmcfg_fallback_slots))
- return 0;
-
for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) {
cfg = &pci_mmcfg_config[cfg_num];
if (cfg->pci_segment == seg &&
@@ -68,13 +64,16 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
u32 base;
if ((bus > 255) || (devfn > 255) || (reg > 4095)) {
- *value = -1;
+err: *value = -1;
return -EINVAL;
}
+ if (reg < 256)
+ return pci_conf1_read(seg,bus,devfn,reg,len,value);
+
base = get_base_addr(seg, bus, devfn);
if (!base)
- return pci_conf1_read(seg,bus,devfn,reg,len,value);
+ goto err;
spin_lock_irqsave(&pci_config_lock, flags);
@@ -105,9 +104,12 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
if ((bus > 255) || (devfn > 255) || (reg > 4095))
return -EINVAL;
+ if (reg < 256)
+ return pci_conf1_write(seg,bus,devfn,reg,len,value);
+
base = get_base_addr(seg, bus, devfn);
if (!base)
- return pci_conf1_write(seg,bus,devfn,reg,len,value);
+ return -EINVAL;
spin_lock_irqsave(&pci_config_lock, flags);
@@ -134,12 +136,6 @@ static struct pci_raw_ops pci_mmcfg = {
.write = pci_mmcfg_write,
};
-int __init pci_mmcfg_arch_reachable(unsigned int seg, unsigned int bus,
- unsigned int devfn)
-{
- return get_base_addr(seg, bus, devfn) != 0;
-}
-
int __init pci_mmcfg_arch_init(void)
{
printk(KERN_INFO "PCI: Using MMCONFIG\n");
diff --git a/arch/x86/pci/mmconfig_64.c b/arch/x86/pci/mmconfig_64.c
index 4095e4d..c4cf318 100644
--- a/arch/x86/pci/mmconfig_64.c
+++ b/arch/x86/pci/mmconfig_64.c
@@ -40,9 +40,7 @@ static char __iomem *get_virt(unsigned int seg, unsigned bus)
static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
{
char __iomem *addr;
- if (seg == 0 && bus < PCI_MMCFG_MAX_CHECK_BUS &&
- test_bit(32*bus + PCI_SLOT(devfn), pci_mmcfg_fallback_slots))
- return NULL;
+
addr = get_virt(seg, bus);
if (!addr)
return NULL;
@@ -56,13 +54,16 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
/* Why do we have this when nobody checks it. How about a BUG()!? -AK */
if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) {
- *value = -1;
+err: *value = -1;
return -EINVAL;
}
+ if (reg < 256)
+ return pci_conf1_read(seg,bus,devfn,reg,len,value);
+
addr = pci_dev_base(seg, bus, devfn);
if (!addr)
- return pci_conf1_read(seg,bus,devfn,reg,len,value);
+ goto err;
switch (len) {
case 1:
@@ -88,9 +89,12 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
return -EINVAL;
+ if (reg < 256)
+ return pci_conf1_write(seg,bus,devfn,reg,len,value);
+
addr = pci_dev_base(seg, bus, devfn);
if (!addr)
- return pci_conf1_write(seg,bus,devfn,reg,len,value);
+ return -EINVAL;
switch (len) {
case 1:
@@ -126,12 +130,6 @@ static void __iomem * __init mcfg_ioremap(struct acpi_mcfg_allocation *cfg)
return addr;
}
-int __init pci_mmcfg_arch_reachable(unsigned int seg, unsigned int bus,
- unsigned int devfn)
-{
- return pci_dev_base(seg, bus, devfn) != NULL;
-}
-
int __init pci_mmcfg_arch_init(void)
{
int i;
diff --git a/arch/x86/pci/pci.h b/arch/x86/pci/pci.h
index ac56d39..36cb44c 100644
--- a/arch/x86/pci/pci.h
+++ b/arch/x86/pci/pci.h
@@ -98,13 +98,6 @@ extern void pcibios_sort(void);
/* pci-mmconfig.c */
-/* Verify the first 16 busses. We assume that systems with more busses
- get MCFG right. */
-#define PCI_MMCFG_MAX_CHECK_BUS 16
-extern DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS);
-
-extern int __init pci_mmcfg_arch_reachable(unsigned int seg, unsigned int bus,
- unsigned int devfn);
extern int __init pci_mmcfg_arch_init(void);
/*
--
Intel are signing my paycheques ... these opinions are still mine
"Bill, look, we understand that you're interested in selling us this
operating system, but compare it to ours. We can't possibly take such
a retrograde step."
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/