Merge git://git.infradead.org/mtd-2.6
[linux-2.6-block.git] / arch / i386 / pci / mmconfig.c
CommitLineData
1da177e4
LT
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>
54549391 14#include <linux/acpi.h>
40dd2d20 15#include <linux/dmi.h>
946f2ee5 16#include <asm/e820.h>
1da177e4
LT
17#include "pci.h"
18
ead2bfeb
CE
19/* aperture is up to 256MB but BIOS may reserve less */
20#define MMCONFIG_APER_MIN (2 * 1024*1024)
21#define MMCONFIG_APER_MAX (256 * 1024*1024)
946f2ee5 22
8c30b1a7
AK
23/* Assume systems with more busses have correct MCFG */
24#define MAX_CHECK_BUS 16
25
1da177e4
LT
26#define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG))
27
28/* The base address of the last MMCONFIG device accessed */
29static u32 mmcfg_last_accessed_device;
30
8c30b1a7 31static DECLARE_BITMAP(fallback_slots, MAX_CHECK_BUS*32);
d6ece549 32
1da177e4
LT
33/*
34 * Functions for accessing PCI configuration space with MMCONFIG accesses
35 */
d6ece549 36static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
d57e26ce
GKH
37{
38 int cfg_num = -1;
39 struct acpi_table_mcfg_config *cfg;
40
8c30b1a7
AK
41 if (seg == 0 && bus < MAX_CHECK_BUS &&
42 test_bit(PCI_SLOT(devfn) + 32*bus, fallback_slots))
d6ece549
AK
43 return 0;
44
d57e26ce
GKH
45 while (1) {
46 ++cfg_num;
47 if (cfg_num >= pci_mmcfg_config_num) {
3103039c 48 break;
d57e26ce
GKH
49 }
50 cfg = &pci_mmcfg_config[cfg_num];
51 if (cfg->pci_segment_group_number != seg)
52 continue;
53 if ((cfg->start_bus_number <= bus) &&
54 (cfg->end_bus_number >= bus))
55 return cfg->base_address;
56 }
3103039c
AK
57
58 /* Handle more broken MCFG tables on Asus etc.
59 They only contain a single entry for bus 0-0. Assume
60 this applies to all busses. */
61 cfg = &pci_mmcfg_config[0];
62 if (pci_mmcfg_config_num == 1 &&
63 cfg->pci_segment_group_number == 0 &&
64 (cfg->start_bus_number | cfg->end_bus_number) == 0)
65 return cfg->base_address;
66
67 /* Fall back to type 0 */
68 return 0;
d57e26ce 69}
1da177e4 70
928cf8c6 71static inline void pci_exp_set_dev_base(unsigned int base, int bus, int devfn)
1da177e4 72{
928cf8c6 73 u32 dev_base = base | (bus << 20) | (devfn << 12);
1da177e4
LT
74 if (dev_base != mmcfg_last_accessed_device) {
75 mmcfg_last_accessed_device = dev_base;
76 set_fixmap_nocache(FIX_PCIE_MCFG, dev_base);
77 }
78}
79
80static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
81 unsigned int devfn, int reg, int len, u32 *value)
82{
83 unsigned long flags;
928cf8c6 84 u32 base;
1da177e4 85
ecc16ba9 86 if ((bus > 255) || (devfn > 255) || (reg > 4095)) {
49c93e84 87 *value = -1;
1da177e4 88 return -EINVAL;
49c93e84 89 }
1da177e4 90
d6ece549 91 base = get_base_addr(seg, bus, devfn);
928cf8c6
AK
92 if (!base)
93 return pci_conf1_read(seg,bus,devfn,reg,len,value);
94
1da177e4
LT
95 spin_lock_irqsave(&pci_config_lock, flags);
96
928cf8c6 97 pci_exp_set_dev_base(base, bus, devfn);
1da177e4
LT
98
99 switch (len) {
100 case 1:
101 *value = readb(mmcfg_virt_addr + reg);
102 break;
103 case 2:
104 *value = readw(mmcfg_virt_addr + reg);
105 break;
106 case 4:
107 *value = readl(mmcfg_virt_addr + reg);
108 break;
109 }
110
111 spin_unlock_irqrestore(&pci_config_lock, flags);
112
113 return 0;
114}
115
116static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
117 unsigned int devfn, int reg, int len, u32 value)
118{
119 unsigned long flags;
928cf8c6 120 u32 base;
1da177e4
LT
121
122 if ((bus > 255) || (devfn > 255) || (reg > 4095))
123 return -EINVAL;
124
d6ece549 125 base = get_base_addr(seg, bus, devfn);
928cf8c6
AK
126 if (!base)
127 return pci_conf1_write(seg,bus,devfn,reg,len,value);
128
1da177e4
LT
129 spin_lock_irqsave(&pci_config_lock, flags);
130
928cf8c6 131 pci_exp_set_dev_base(base, bus, devfn);
1da177e4
LT
132
133 switch (len) {
134 case 1:
135 writeb(value, mmcfg_virt_addr + reg);
136 break;
137 case 2:
138 writew(value, mmcfg_virt_addr + reg);
139 break;
140 case 4:
141 writel(value, mmcfg_virt_addr + reg);
142 break;
143 }
144
145 spin_unlock_irqrestore(&pci_config_lock, flags);
146
147 return 0;
148}
149
150static struct pci_raw_ops pci_mmcfg = {
151 .read = pci_mmcfg_read,
152 .write = pci_mmcfg_write,
153};
154
d6ece549
AK
155/* K8 systems have some devices (typically in the builtin northbridge)
156 that are only accessible using type1
157 Normally this can be expressed in the MCFG by not listing them
158 and assigning suitable _SEGs, but this isn't implemented in some BIOS.
159 Instead try to discover all devices on bus 0 that are unreachable using MM
8c30b1a7 160 and fallback for them. */
d6ece549
AK
161static __init void unreachable_devices(void)
162{
8c30b1a7 163 int i, k;
d6ece549
AK
164 unsigned long flags;
165
8c30b1a7
AK
166 for (k = 0; k < MAX_CHECK_BUS; k++) {
167 for (i = 0; i < 32; i++) {
168 u32 val1;
169 u32 addr;
170
171 pci_conf1_read(0, k, PCI_DEVFN(i, 0), 0, 4, &val1);
172 if (val1 == 0xffffffff)
173 continue;
174
175 /* Locking probably not needed, but safer */
176 spin_lock_irqsave(&pci_config_lock, flags);
177 addr = get_base_addr(0, k, PCI_DEVFN(i, 0));
178 if (addr != 0)
179 pci_exp_set_dev_base(addr, k, PCI_DEVFN(i, 0));
180 if (addr == 0 ||
181 readl((u32 __iomem *)mmcfg_virt_addr) != val1) {
fd4dc27c 182 set_bit(i + 32*k, fallback_slots);
8c30b1a7
AK
183 printk(KERN_NOTICE
184 "PCI: No mmconfig possible on %x:%x\n", k, i);
185 }
186 spin_unlock_irqrestore(&pci_config_lock, flags);
187 }
d6ece549
AK
188 }
189}
190
40dd2d20
AK
191static int disable_mcfg(struct dmi_system_id *d)
192{
193 printk("PCI: %s detected. Disabling MCFG.\n", d->ident);
194 pci_probe &= ~PCI_PROBE_MMCONF;
195 return 0;
196}
197
198static struct dmi_system_id __initdata dmi_bad_mcfg[] = {
199 /* Has broken MCFG table that makes the system hang when used */
200 {
201 .callback = disable_mcfg,
202 .ident = "Intel D3C5105 SDV",
203 .matches = {
204 DMI_MATCH(DMI_BIOS_VENDOR, "Intel"),
205 DMI_MATCH(DMI_BOARD_NAME, "D26928"),
206 },
207 },
208 {}
209};
210
92c05fc1 211void __init pci_mmcfg_init(void)
1da177e4 212{
40dd2d20
AK
213 dmi_check_system(dmi_bad_mcfg);
214
215 if ((pci_probe & (PCI_PROBE_MMCONF_FORCE|PCI_PROBE_MMCONF)) == 0)
92c05fc1 216 return;
54549391
GKH
217
218 acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
219 if ((pci_mmcfg_config_num == 0) ||
220 (pci_mmcfg_config == NULL) ||
221 (pci_mmcfg_config[0].base_address == 0))
92c05fc1 222 return;
1da177e4 223
1da177e4
LT
224 printk(KERN_INFO "PCI: Using MMCONFIG\n");
225 raw_pci_ops = &pci_mmcfg;
226 pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
227
d6ece549 228 unreachable_devices();
1da177e4 229}