]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/i386/pci/mmconfig.c
[PATCH] i386/x86-64: Check that MCFG points to an e820 reserved area
[linux-2.6-omap-h63xx.git] / arch / i386 / pci / mmconfig.c
1 /*
2  * Copyright (C) 2004 Matthew Wilcox <matthew@wil.cx>
3  * Copyright (C) 2004 Intel Corp.
4  *
5  * This code is released under the GNU General Public License version 2.
6  */
7
8 /*
9  * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
10  */
11
12 #include <linux/pci.h>
13 #include <linux/init.h>
14 #include <linux/acpi.h>
15 #include <asm/e820.h>
16 #include "pci.h"
17
18 #define MMCONFIG_APER_SIZE (256*1024*1024)
19
20 #define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG))
21
22 /* The base address of the last MMCONFIG device accessed */
23 static u32 mmcfg_last_accessed_device;
24
25 static DECLARE_BITMAP(fallback_slots, 32);
26
27 /*
28  * Functions for accessing PCI configuration space with MMCONFIG accesses
29  */
30 static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
31 {
32         int cfg_num = -1;
33         struct acpi_table_mcfg_config *cfg;
34
35         if (seg == 0 && bus == 0 &&
36             test_bit(PCI_SLOT(devfn), fallback_slots))
37                 return 0;
38
39         while (1) {
40                 ++cfg_num;
41                 if (cfg_num >= pci_mmcfg_config_num) {
42                         break;
43                 }
44                 cfg = &pci_mmcfg_config[cfg_num];
45                 if (cfg->pci_segment_group_number != seg)
46                         continue;
47                 if ((cfg->start_bus_number <= bus) &&
48                     (cfg->end_bus_number >= bus))
49                         return cfg->base_address;
50         }
51
52         /* Handle more broken MCFG tables on Asus etc.
53            They only contain a single entry for bus 0-0. Assume
54            this applies to all busses. */
55         cfg = &pci_mmcfg_config[0];
56         if (pci_mmcfg_config_num == 1 &&
57                 cfg->pci_segment_group_number == 0 &&
58                 (cfg->start_bus_number | cfg->end_bus_number) == 0)
59                 return cfg->base_address;
60
61         /* Fall back to type 0 */
62         return 0;
63 }
64
65 static inline void pci_exp_set_dev_base(unsigned int base, int bus, int devfn)
66 {
67         u32 dev_base = base | (bus << 20) | (devfn << 12);
68         if (dev_base != mmcfg_last_accessed_device) {
69                 mmcfg_last_accessed_device = dev_base;
70                 set_fixmap_nocache(FIX_PCIE_MCFG, dev_base);
71         }
72 }
73
74 static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
75                           unsigned int devfn, int reg, int len, u32 *value)
76 {
77         unsigned long flags;
78         u32 base;
79
80         if (!value || (bus > 255) || (devfn > 255) || (reg > 4095))
81                 return -EINVAL;
82
83         base = get_base_addr(seg, bus, devfn);
84         if (!base)
85                 return pci_conf1_read(seg,bus,devfn,reg,len,value);
86
87         spin_lock_irqsave(&pci_config_lock, flags);
88
89         pci_exp_set_dev_base(base, bus, devfn);
90
91         switch (len) {
92         case 1:
93                 *value = readb(mmcfg_virt_addr + reg);
94                 break;
95         case 2:
96                 *value = readw(mmcfg_virt_addr + reg);
97                 break;
98         case 4:
99                 *value = readl(mmcfg_virt_addr + reg);
100                 break;
101         }
102
103         spin_unlock_irqrestore(&pci_config_lock, flags);
104
105         return 0;
106 }
107
108 static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
109                            unsigned int devfn, int reg, int len, u32 value)
110 {
111         unsigned long flags;
112         u32 base;
113
114         if ((bus > 255) || (devfn > 255) || (reg > 4095)) 
115                 return -EINVAL;
116
117         base = get_base_addr(seg, bus, devfn);
118         if (!base)
119                 return pci_conf1_write(seg,bus,devfn,reg,len,value);
120
121         spin_lock_irqsave(&pci_config_lock, flags);
122
123         pci_exp_set_dev_base(base, bus, devfn);
124
125         switch (len) {
126         case 1:
127                 writeb(value, mmcfg_virt_addr + reg);
128                 break;
129         case 2:
130                 writew(value, mmcfg_virt_addr + reg);
131                 break;
132         case 4:
133                 writel(value, mmcfg_virt_addr + reg);
134                 break;
135         }
136
137         spin_unlock_irqrestore(&pci_config_lock, flags);
138
139         return 0;
140 }
141
142 static struct pci_raw_ops pci_mmcfg = {
143         .read =         pci_mmcfg_read,
144         .write =        pci_mmcfg_write,
145 };
146
147 /* K8 systems have some devices (typically in the builtin northbridge)
148    that are only accessible using type1
149    Normally this can be expressed in the MCFG by not listing them
150    and assigning suitable _SEGs, but this isn't implemented in some BIOS.
151    Instead try to discover all devices on bus 0 that are unreachable using MM
152    and fallback for them.
153    We only do this for bus 0/seg 0 */
154 static __init void unreachable_devices(void)
155 {
156         int i;
157         unsigned long flags;
158
159         for (i = 0; i < 32; i++) {
160                 u32 val1;
161                 u32 addr;
162
163                 pci_conf1_read(0, 0, PCI_DEVFN(i, 0), 0, 4, &val1);
164                 if (val1 == 0xffffffff)
165                         continue;
166
167                 /* Locking probably not needed, but safer */
168                 spin_lock_irqsave(&pci_config_lock, flags);
169                 addr = get_base_addr(0, 0, PCI_DEVFN(i, 0));
170                 if (addr != 0)
171                         pci_exp_set_dev_base(addr, 0, PCI_DEVFN(i, 0));
172                 if (addr == 0 || readl((u32 __iomem *)mmcfg_virt_addr) != val1)
173                         set_bit(i, fallback_slots);
174                 spin_unlock_irqrestore(&pci_config_lock, flags);
175         }
176 }
177
178 void __init pci_mmcfg_init(void)
179 {
180         if ((pci_probe & PCI_PROBE_MMCONF) == 0)
181                 return;
182
183         acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
184         if ((pci_mmcfg_config_num == 0) ||
185             (pci_mmcfg_config == NULL) ||
186             (pci_mmcfg_config[0].base_address == 0))
187                 return;
188
189         if (!e820_all_mapped(pci_mmcfg_config[0].base_address,
190                         pci_mmcfg_config[0].base_address + MMCONFIG_APER_SIZE,
191                         E820_RESERVED)) {
192                 printk(KERN_ERR "PCI: BIOS Bug: MCFG area is not E820-reserved\n");
193                 printk(KERN_ERR "PCI: Not using MMCONFIG.\n");
194                 return;
195         }
196
197         printk(KERN_INFO "PCI: Using MMCONFIG\n");
198         raw_pci_ops = &pci_mmcfg;
199         pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
200
201         unreachable_devices();
202 }