aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIvan Kokshaysky <ink@jurassic.park.msu.ru>2008-01-14 17:31:09 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-10 15:52:45 -0500
commita0ca9909609470ad779b9b9cc68ce96e975afff7 (patch)
treeaf1ce8cdf6e927e25ad92869849456916e236fbf
parent7cf712db6087342e5e7e259d3883a7b5ac3212d1 (diff)
PCI x86: always use conf1 to access config space below 256 bytes
Thanks to Loic Prylli <loic@myri.com>, 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@jurassic.park.msu.ru> Signed-off-by: Matthew Wilcox <willy@linux.intel.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--arch/x86/pci/mmconfig-shared.c35
-rw-r--r--arch/x86/pci/mmconfig_32.c22
-rw-r--r--arch/x86/pci/mmconfig_64.c22
-rw-r--r--arch/x86/pci/pci.h7
4 files changed, 19 insertions, 67 deletions
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
index 4df637e34f81..6b521d389327 100644
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -22,42 +22,9 @@
22#define MMCONFIG_APER_MIN (2 * 1024*1024) 22#define MMCONFIG_APER_MIN (2 * 1024*1024)
23#define MMCONFIG_APER_MAX (256 * 1024*1024) 23#define MMCONFIG_APER_MAX (256 * 1024*1024)
24 24
25DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS);
26
27/* Indicate if the mmcfg resources have been placed into the resource table. */ 25/* Indicate if the mmcfg resources have been placed into the resource table. */
28static int __initdata pci_mmcfg_resources_inserted; 26static int __initdata pci_mmcfg_resources_inserted;
29 27
30/* K8 systems have some devices (typically in the builtin northbridge)
31 that are only accessible using type1
32 Normally this can be expressed in the MCFG by not listing them
33 and assigning suitable _SEGs, but this isn't implemented in some BIOS.
34 Instead try to discover all devices on bus 0 that are unreachable using MM
35 and fallback for them. */
36static void __init unreachable_devices(void)
37{
38 int i, bus;
39 /* Use the max bus number from ACPI here? */
40 for (bus = 0; bus < PCI_MMCFG_MAX_CHECK_BUS; bus++) {
41 for (i = 0; i < 32; i++) {
42 unsigned int devfn = PCI_DEVFN(i, 0);
43 u32 val1, val2;
44
45 pci_conf1_read(0, bus, devfn, 0, 4, &val1);
46 if (val1 == 0xffffffff)
47 continue;
48
49 if (pci_mmcfg_arch_reachable(0, bus, devfn)) {
50 raw_pci_ops->read(0, bus, devfn, 0, 4, &val2);
51 if (val1 == val2)
52 continue;
53 }
54 set_bit(i + 32 * bus, pci_mmcfg_fallback_slots);
55 printk(KERN_NOTICE "PCI: No mmconfig possible on device"
56 " %02x:%02x\n", bus, i);
57 }
58 }
59}
60
61static const char __init *pci_mmcfg_e7520(void) 28static const char __init *pci_mmcfg_e7520(void)
62{ 29{
63 u32 win; 30 u32 win;
@@ -270,8 +237,6 @@ void __init pci_mmcfg_init(int type)
270 return; 237 return;
271 238
272 if (pci_mmcfg_arch_init()) { 239 if (pci_mmcfg_arch_init()) {
273 if (type == 1)
274 unreachable_devices();
275 if (known_bridge) 240 if (known_bridge)
276 pci_mmcfg_insert_resources(IORESOURCE_BUSY); 241 pci_mmcfg_insert_resources(IORESOURCE_BUSY);
277 pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF; 242 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 1bf5816d34c8..7b75e6513436 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)
30 struct acpi_mcfg_allocation *cfg; 30 struct acpi_mcfg_allocation *cfg;
31 int cfg_num; 31 int cfg_num;
32 32
33 if (seg == 0 && bus < PCI_MMCFG_MAX_CHECK_BUS &&
34 test_bit(PCI_SLOT(devfn) + 32*bus, pci_mmcfg_fallback_slots))
35 return 0;
36
37 for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) { 33 for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) {
38 cfg = &pci_mmcfg_config[cfg_num]; 34 cfg = &pci_mmcfg_config[cfg_num];
39 if (cfg->pci_segment == seg && 35 if (cfg->pci_segment == seg &&
@@ -68,13 +64,16 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
68 u32 base; 64 u32 base;
69 65
70 if ((bus > 255) || (devfn > 255) || (reg > 4095)) { 66 if ((bus > 255) || (devfn > 255) || (reg > 4095)) {
71 *value = -1; 67err: *value = -1;
72 return -EINVAL; 68 return -EINVAL;
73 } 69 }
74 70
71 if (reg < 256)
72 return pci_conf1_read(seg,bus,devfn,reg,len,value);
73
75 base = get_base_addr(seg, bus, devfn); 74 base = get_base_addr(seg, bus, devfn);
76 if (!base) 75 if (!base)
77 return pci_conf1_read(seg,bus,devfn,reg,len,value); 76 goto err;
78 77
79 spin_lock_irqsave(&pci_config_lock, flags); 78 spin_lock_irqsave(&pci_config_lock, flags);
80 79
@@ -105,9 +104,12 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
105 if ((bus > 255) || (devfn > 255) || (reg > 4095)) 104 if ((bus > 255) || (devfn > 255) || (reg > 4095))
106 return -EINVAL; 105 return -EINVAL;
107 106
107 if (reg < 256)
108 return pci_conf1_write(seg,bus,devfn,reg,len,value);
109
108 base = get_base_addr(seg, bus, devfn); 110 base = get_base_addr(seg, bus, devfn);
109 if (!base) 111 if (!base)
110 return pci_conf1_write(seg,bus,devfn,reg,len,value); 112 return -EINVAL;
111 113
112 spin_lock_irqsave(&pci_config_lock, flags); 114 spin_lock_irqsave(&pci_config_lock, flags);
113 115
@@ -134,12 +136,6 @@ static struct pci_raw_ops pci_mmcfg = {
134 .write = pci_mmcfg_write, 136 .write = pci_mmcfg_write,
135}; 137};
136 138
137int __init pci_mmcfg_arch_reachable(unsigned int seg, unsigned int bus,
138 unsigned int devfn)
139{
140 return get_base_addr(seg, bus, devfn) != 0;
141}
142
143int __init pci_mmcfg_arch_init(void) 139int __init pci_mmcfg_arch_init(void)
144{ 140{
145 printk(KERN_INFO "PCI: Using MMCONFIG\n"); 141 printk(KERN_INFO "PCI: Using MMCONFIG\n");
diff --git a/arch/x86/pci/mmconfig_64.c b/arch/x86/pci/mmconfig_64.c
index 4095e4d66a1d..c4cf318e44a9 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)
40static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn) 40static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
41{ 41{
42 char __iomem *addr; 42 char __iomem *addr;
43 if (seg == 0 && bus < PCI_MMCFG_MAX_CHECK_BUS && 43
44 test_bit(32*bus + PCI_SLOT(devfn), pci_mmcfg_fallback_slots))
45 return NULL;
46 addr = get_virt(seg, bus); 44 addr = get_virt(seg, bus);
47 if (!addr) 45 if (!addr)
48 return NULL; 46 return NULL;
@@ -56,13 +54,16 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
56 54
57 /* Why do we have this when nobody checks it. How about a BUG()!? -AK */ 55 /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
58 if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) { 56 if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) {
59 *value = -1; 57err: *value = -1;
60 return -EINVAL; 58 return -EINVAL;
61 } 59 }
62 60
61 if (reg < 256)
62 return pci_conf1_read(seg,bus,devfn,reg,len,value);
63
63 addr = pci_dev_base(seg, bus, devfn); 64 addr = pci_dev_base(seg, bus, devfn);
64 if (!addr) 65 if (!addr)
65 return pci_conf1_read(seg,bus,devfn,reg,len,value); 66 goto err;
66 67
67 switch (len) { 68 switch (len) {
68 case 1: 69 case 1:
@@ -88,9 +89,12 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
88 if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) 89 if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
89 return -EINVAL; 90 return -EINVAL;
90 91
92 if (reg < 256)
93 return pci_conf1_write(seg,bus,devfn,reg,len,value);
94
91 addr = pci_dev_base(seg, bus, devfn); 95 addr = pci_dev_base(seg, bus, devfn);
92 if (!addr) 96 if (!addr)
93 return pci_conf1_write(seg,bus,devfn,reg,len,value); 97 return -EINVAL;
94 98
95 switch (len) { 99 switch (len) {
96 case 1: 100 case 1:
@@ -126,12 +130,6 @@ static void __iomem * __init mcfg_ioremap(struct acpi_mcfg_allocation *cfg)
126 return addr; 130 return addr;
127} 131}
128 132
129int __init pci_mmcfg_arch_reachable(unsigned int seg, unsigned int bus,
130 unsigned int devfn)
131{
132 return pci_dev_base(seg, bus, devfn) != NULL;
133}
134
135int __init pci_mmcfg_arch_init(void) 133int __init pci_mmcfg_arch_init(void)
136{ 134{
137 int i; 135 int i;
diff --git a/arch/x86/pci/pci.h b/arch/x86/pci/pci.h
index ac56d3916c50..36cb44c397c3 100644
--- a/arch/x86/pci/pci.h
+++ b/arch/x86/pci/pci.h
@@ -98,13 +98,6 @@ extern void pcibios_sort(void);
98 98
99/* pci-mmconfig.c */ 99/* pci-mmconfig.c */
100 100
101/* Verify the first 16 busses. We assume that systems with more busses
102 get MCFG right. */
103#define PCI_MMCFG_MAX_CHECK_BUS 16
104extern DECLARE_BITMAP(pci_mmcfg_fallback_slots, 32*PCI_MMCFG_MAX_CHECK_BUS);
105
106extern int __init pci_mmcfg_arch_reachable(unsigned int seg, unsigned int bus,
107 unsigned int devfn);
108extern int __init pci_mmcfg_arch_init(void); 101extern int __init pci_mmcfg_arch_init(void);
109 102
110/* 103/*