aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64')
-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);