aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/i386/pci/direct.c4
-rw-r--r--arch/i386/pci/mmconfig.c24
-rw-r--r--arch/i386/pci/pci.h7
-rw-r--r--arch/x86_64/pci/mmconfig.c29
4 files changed, 45 insertions, 19 deletions
diff --git a/arch/i386/pci/direct.c b/arch/i386/pci/direct.c
index 94331d6be7a3..e3ac502bf2fb 100644
--- a/arch/i386/pci/direct.c
+++ b/arch/i386/pci/direct.c
@@ -13,7 +13,7 @@
13#define PCI_CONF1_ADDRESS(bus, devfn, reg) \ 13#define PCI_CONF1_ADDRESS(bus, devfn, reg) \
14 (0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3)) 14 (0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))
15 15
16static int pci_conf1_read(unsigned int seg, unsigned int bus, 16int pci_conf1_read(unsigned int seg, unsigned int bus,
17 unsigned int devfn, int reg, int len, u32 *value) 17 unsigned int devfn, int reg, int len, u32 *value)
18{ 18{
19 unsigned long flags; 19 unsigned long flags;
@@ -42,7 +42,7 @@ static int pci_conf1_read(unsigned int seg, unsigned int bus,
42 return 0; 42 return 0;
43} 43}
44 44
45static int pci_conf1_write(unsigned int seg, unsigned int bus, 45int pci_conf1_write(unsigned int seg, unsigned int bus,
46 unsigned int devfn, int reg, int len, u32 value) 46 unsigned int devfn, int reg, int len, u32 value)
47{ 47{
48 unsigned long flags; 48 unsigned long flags;
diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c
index dfbf80cff834..cc787a7c030c 100644
--- a/arch/i386/pci/mmconfig.c
+++ b/arch/i386/pci/mmconfig.c
@@ -30,10 +30,8 @@ static u32 get_base_addr(unsigned int seg, int bus)
30 while (1) { 30 while (1) {
31 ++cfg_num; 31 ++cfg_num;
32 if (cfg_num >= pci_mmcfg_config_num) { 32 if (cfg_num >= pci_mmcfg_config_num) {
33 /* something bad is going on, no cfg table is found. */ 33 /* Not found - fallback to type 1 */
34 /* so we fall back to the old way we used to do this */ 34 return 0;
35 /* and just rely on the first entry to be correct. */
36 return pci_mmcfg_config[0].base_address;
37 } 35 }
38 cfg = &pci_mmcfg_config[cfg_num]; 36 cfg = &pci_mmcfg_config[cfg_num];
39 if (cfg->pci_segment_group_number != seg) 37 if (cfg->pci_segment_group_number != seg)
@@ -44,9 +42,9 @@ static u32 get_base_addr(unsigned int seg, int bus)
44 } 42 }
45} 43}
46 44
47static inline void pci_exp_set_dev_base(unsigned int seg, int bus, int devfn) 45static inline void pci_exp_set_dev_base(unsigned int base, int bus, int devfn)
48{ 46{
49 u32 dev_base = get_base_addr(seg, bus) | (bus << 20) | (devfn << 12); 47 u32 dev_base = base | (bus << 20) | (devfn << 12);
50 if (dev_base != mmcfg_last_accessed_device) { 48 if (dev_base != mmcfg_last_accessed_device) {
51 mmcfg_last_accessed_device = dev_base; 49 mmcfg_last_accessed_device = dev_base;
52 set_fixmap_nocache(FIX_PCIE_MCFG, dev_base); 50 set_fixmap_nocache(FIX_PCIE_MCFG, dev_base);
@@ -57,13 +55,18 @@ static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
57 unsigned int devfn, int reg, int len, u32 *value) 55 unsigned int devfn, int reg, int len, u32 *value)
58{ 56{
59 unsigned long flags; 57 unsigned long flags;
58 u32 base;
60 59
61 if (!value || (bus > 255) || (devfn > 255) || (reg > 4095)) 60 if (!value || (bus > 255) || (devfn > 255) || (reg > 4095))
62 return -EINVAL; 61 return -EINVAL;
63 62
63 base = get_base_addr(seg, bus);
64 if (!base)
65 return pci_conf1_read(seg,bus,devfn,reg,len,value);
66
64 spin_lock_irqsave(&pci_config_lock, flags); 67 spin_lock_irqsave(&pci_config_lock, flags);
65 68
66 pci_exp_set_dev_base(seg, bus, devfn); 69 pci_exp_set_dev_base(base, bus, devfn);
67 70
68 switch (len) { 71 switch (len) {
69 case 1: 72 case 1:
@@ -86,13 +89,18 @@ static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
86 unsigned int devfn, int reg, int len, u32 value) 89 unsigned int devfn, int reg, int len, u32 value)
87{ 90{
88 unsigned long flags; 91 unsigned long flags;
92 u32 base;
89 93
90 if ((bus > 255) || (devfn > 255) || (reg > 4095)) 94 if ((bus > 255) || (devfn > 255) || (reg > 4095))
91 return -EINVAL; 95 return -EINVAL;
92 96
97 base = get_base_addr(seg, bus);
98 if (!base)
99 return pci_conf1_write(seg,bus,devfn,reg,len,value);
100
93 spin_lock_irqsave(&pci_config_lock, flags); 101 spin_lock_irqsave(&pci_config_lock, flags);
94 102
95 pci_exp_set_dev_base(seg, bus, devfn); 103 pci_exp_set_dev_base(base, bus, devfn);
96 104
97 switch (len) { 105 switch (len) {
98 case 1: 106 case 1:
diff --git a/arch/i386/pci/pci.h b/arch/i386/pci/pci.h
index 127d53ad16be..f550781ec310 100644
--- a/arch/i386/pci/pci.h
+++ b/arch/i386/pci/pci.h
@@ -74,3 +74,10 @@ extern spinlock_t pci_config_lock;
74 74
75extern int (*pcibios_enable_irq)(struct pci_dev *dev); 75extern int (*pcibios_enable_irq)(struct pci_dev *dev);
76extern void (*pcibios_disable_irq)(struct pci_dev *dev); 76extern void (*pcibios_disable_irq)(struct pci_dev *dev);
77
78extern int pci_conf1_write(unsigned int seg, unsigned int bus,
79 unsigned int devfn, int reg, int len, u32 value);
80extern int pci_conf1_read(unsigned int seg, unsigned int bus,
81 unsigned int devfn, int reg, int len, u32 *value);
82
83
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);