aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/pci
diff options
context:
space:
mode:
authorAndi Kleen <ak@suse.de>2005-12-13 01:17:10 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-12-13 01:31:16 -0500
commit928cf8c62763349efc550a12f6518e52c3390906 (patch)
tree5fb257cbdaaebc3814e6df85100712127cdb8526 /arch/x86_64/pci
parentbf5421c309bb89e5106452bc840983b1b4754d61 (diff)
[PATCH] i386/x86-64 Fall back to type 1 access when no entry found
When there is no entry for a bus in MCFG fall back to type1. This is especially important on K8 systems where always some devices can't be accessed using mmconfig (in particular the builtin northbridge doesn't support it for its own devices) Cc: <gregkh@suse.de> Cc: <jgarzik@pobox.com> Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/x86_64/pci')
-rw-r--r--arch/x86_64/pci/mmconfig.c29
1 files changed, 20 insertions, 9 deletions
diff --git a/arch/x86_64/pci/mmconfig.c b/arch/x86_64/pci/mmconfig.c
index a0838c4a94e4..22ff1b07d4e0 100644
--- a/arch/x86_64/pci/mmconfig.c
+++ b/arch/x86_64/pci/mmconfig.c
@@ -19,7 +19,7 @@ struct mmcfg_virt {
19}; 19};
20static struct mmcfg_virt *pci_mmcfg_virt; 20static struct mmcfg_virt *pci_mmcfg_virt;
21 21
22static char *get_virt(unsigned int seg, int bus) 22static char *get_virt(unsigned int seg, unsigned bus)
23{ 23{
24 int cfg_num = -1; 24 int cfg_num = -1;
25 struct acpi_table_mcfg_config *cfg; 25 struct acpi_table_mcfg_config *cfg;
@@ -27,10 +27,9 @@ static char *get_virt(unsigned int seg, int bus)
27 while (1) { 27 while (1) {
28 ++cfg_num; 28 ++cfg_num;
29 if (cfg_num >= pci_mmcfg_config_num) { 29 if (cfg_num >= pci_mmcfg_config_num) {
30 /* something bad is going on, no cfg table is found. */ 30 /* Not found - fall back to type 1. This happens
31 /* so we fall back to the old way we used to do this */ 31 e.g. on the internal devices of a K8 northbridge. */
32 /* and just rely on the first entry to be correct. */ 32 return NULL;
33 return pci_mmcfg_virt[0].virt;
34 } 33 }
35 cfg = pci_mmcfg_virt[cfg_num].cfg; 34 cfg = pci_mmcfg_virt[cfg_num].cfg;
36 if (cfg->pci_segment_group_number != seg) 35 if (cfg->pci_segment_group_number != seg)
@@ -43,18 +42,25 @@ static char *get_virt(unsigned int seg, int bus)
43 42
44static inline char *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn) 43static inline char *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
45{ 44{
46 45 char *addr = get_virt(seg, bus);
47 return get_virt(seg, bus) + ((bus << 20) | (devfn << 12)); 46 if (!addr)
47 return NULL;
48 return addr + ((bus << 20) | (devfn << 12));
48} 49}
49 50
50static int pci_mmcfg_read(unsigned int seg, unsigned int bus, 51static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
51 unsigned int devfn, int reg, int len, u32 *value) 52 unsigned int devfn, int reg, int len, u32 *value)
52{ 53{
53 char *addr = pci_dev_base(seg, bus, devfn); 54 char *addr;
54 55
56 /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
55 if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095))) 57 if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095)))
56 return -EINVAL; 58 return -EINVAL;
57 59
60 addr = pci_dev_base(seg, bus, devfn);
61 if (!addr)
62 return pci_conf1_read(seg,bus,devfn,reg,len,value);
63
58 switch (len) { 64 switch (len) {
59 case 1: 65 case 1:
60 *value = readb(addr + reg); 66 *value = readb(addr + reg);
@@ -73,11 +79,16 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
73static int pci_mmcfg_write(unsigned int seg, unsigned int bus, 79static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
74 unsigned int devfn, int reg, int len, u32 value) 80 unsigned int devfn, int reg, int len, u32 value)
75{ 81{
76 char *addr = pci_dev_base(seg, bus, devfn); 82 char *addr;
77 83
84 /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
78 if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) 85 if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
79 return -EINVAL; 86 return -EINVAL;
80 87
88 addr = pci_dev_base(seg, bus, devfn);
89 if (!addr)
90 return pci_conf1_write(seg,bus,devfn,reg,len,value);
91
81 switch (len) { 92 switch (len) {
82 case 1: 93 case 1:
83 writeb(value, addr + reg); 94 writeb(value, addr + reg);