diff options
Diffstat (limited to 'arch/x86_64')
-rw-r--r-- | arch/x86_64/pci/mmconfig.c | 29 |
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 | }; |
20 | static struct mmcfg_virt *pci_mmcfg_virt; | 20 | static struct mmcfg_virt *pci_mmcfg_virt; |
21 | 21 | ||
22 | static char *get_virt(unsigned int seg, int bus) | 22 | static 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 | ||
44 | static inline char *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn) | 43 | static 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 | ||
50 | static int pci_mmcfg_read(unsigned int seg, unsigned int bus, | 51 | static 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, | |||
73 | static int pci_mmcfg_write(unsigned int seg, unsigned int bus, | 79 | static 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); |