aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-04-01 12:47:12 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-04-01 12:47:12 -0400
commite76e5b2c663ac74ae6a542ac20795c625e36a5cd (patch)
tree2e7271be1f3a26832f4b121839fc4044fbbf27a6 /arch
parent32527bc0e4b4fa7711ad1c923cf64ae72a7ffd9d (diff)
parenteeafda70bf2807544e96fa4e52b2433cd470ff46 (diff)
Merge branch 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6
* 'linux-next' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes/pci-2.6: (88 commits) PCI: fix HT MSI mapping fix PCI: don't enable too much HT MSI mapping x86/PCI: make pci=lastbus=255 work when acpi is on PCI: save and restore PCIe 2.0 registers PCI: update fakephp for bus_id removal PCI: fix kernel oops on bridge removal PCI: fix conflict between SR-IOV and config space sizing powerpc/PCI: include pci.h in powerpc MSI implementation PCI Hotplug: schedule fakephp for feature removal PCI Hotplug: rename legacy_fakephp to fakephp PCI Hotplug: restore fakephp interface with complete reimplementation PCI: Introduce /sys/bus/pci/devices/.../rescan PCI: Introduce /sys/bus/pci/devices/.../remove PCI: Introduce /sys/bus/pci/rescan PCI: Introduce pci_rescan_bus() PCI: do not enable bridges more than once PCI: do not initialize bridges more than once PCI: always scan child buses PCI: pci_scan_slot() returns newly found devices PCI: don't scan existing devices ... Fix trivial append-only conflict in Documentation/feature-removal-schedule.txt
Diffstat (limited to 'arch')
-rw-r--r--arch/alpha/include/asm/pci.h14
-rw-r--r--arch/alpha/kernel/Makefile2
-rw-r--r--arch/alpha/kernel/pci-sysfs.c366
-rw-r--r--arch/powerpc/include/asm/pci.h4
-rw-r--r--arch/powerpc/kernel/msi.c5
-rw-r--r--arch/x86/include/asm/pci.h3
-rw-r--r--arch/x86/kernel/apic/io_apic.c4
-rw-r--r--arch/x86/kernel/pci-dma.c3
-rw-r--r--arch/x86/pci/early.c19
-rw-r--r--arch/x86/pci/fixup.c20
-rw-r--r--arch/x86/pci/legacy.c3
-rw-r--r--arch/x86/pci/mmconfig-shared.c227
-rw-r--r--arch/x86/pci/mmconfig_64.c17
13 files changed, 594 insertions, 93 deletions
diff --git a/arch/alpha/include/asm/pci.h b/arch/alpha/include/asm/pci.h
index 2a14302c17a..cb04eaa6ba3 100644
--- a/arch/alpha/include/asm/pci.h
+++ b/arch/alpha/include/asm/pci.h
@@ -273,4 +273,18 @@ struct pci_dev *alpha_gendev_to_pci(struct device *dev);
273 273
274extern struct pci_dev *isa_bridge; 274extern struct pci_dev *isa_bridge;
275 275
276extern int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val,
277 size_t count);
278extern int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val,
279 size_t count);
280extern int pci_mmap_legacy_page_range(struct pci_bus *bus,
281 struct vm_area_struct *vma,
282 enum pci_mmap_state mmap_state);
283extern void pci_adjust_legacy_attr(struct pci_bus *bus,
284 enum pci_mmap_state mmap_type);
285#define HAVE_PCI_LEGACY 1
286
287extern int pci_create_resource_files(struct pci_dev *dev);
288extern void pci_remove_resource_files(struct pci_dev *dev);
289
276#endif /* __ALPHA_PCI_H */ 290#endif /* __ALPHA_PCI_H */
diff --git a/arch/alpha/kernel/Makefile b/arch/alpha/kernel/Makefile
index b4697759a12..a427538252f 100644
--- a/arch/alpha/kernel/Makefile
+++ b/arch/alpha/kernel/Makefile
@@ -12,7 +12,7 @@ obj-y := entry.o traps.o process.o init_task.o osf_sys.o irq.o \
12 12
13obj-$(CONFIG_VGA_HOSE) += console.o 13obj-$(CONFIG_VGA_HOSE) += console.o
14obj-$(CONFIG_SMP) += smp.o 14obj-$(CONFIG_SMP) += smp.o
15obj-$(CONFIG_PCI) += pci.o pci_iommu.o 15obj-$(CONFIG_PCI) += pci.o pci_iommu.o pci-sysfs.o
16obj-$(CONFIG_SRM_ENV) += srm_env.o 16obj-$(CONFIG_SRM_ENV) += srm_env.o
17obj-$(CONFIG_MODULES) += module.o 17obj-$(CONFIG_MODULES) += module.o
18 18
diff --git a/arch/alpha/kernel/pci-sysfs.c b/arch/alpha/kernel/pci-sysfs.c
new file mode 100644
index 00000000000..6ea822e7f72
--- /dev/null
+++ b/arch/alpha/kernel/pci-sysfs.c
@@ -0,0 +1,366 @@
1/*
2 * arch/alpha/kernel/pci-sysfs.c
3 *
4 * Copyright (C) 2009 Ivan Kokshaysky
5 *
6 * Alpha PCI resource files.
7 *
8 * Loosely based on generic HAVE_PCI_MMAP implementation in
9 * drivers/pci/pci-sysfs.c
10 */
11
12#include <linux/sched.h>
13#include <linux/pci.h>
14
15static int hose_mmap_page_range(struct pci_controller *hose,
16 struct vm_area_struct *vma,
17 enum pci_mmap_state mmap_type, int sparse)
18{
19 unsigned long base;
20
21 if (mmap_type == pci_mmap_mem)
22 base = sparse ? hose->sparse_mem_base : hose->dense_mem_base;
23 else
24 base = sparse ? hose->sparse_io_base : hose->dense_io_base;
25
26 vma->vm_pgoff += base >> PAGE_SHIFT;
27 vma->vm_flags |= (VM_IO | VM_RESERVED);
28
29 return io_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
30 vma->vm_end - vma->vm_start,
31 vma->vm_page_prot);
32}
33
34static int __pci_mmap_fits(struct pci_dev *pdev, int num,
35 struct vm_area_struct *vma, int sparse)
36{
37 unsigned long nr, start, size;
38 int shift = sparse ? 5 : 0;
39
40 nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
41 start = vma->vm_pgoff;
42 size = ((pci_resource_len(pdev, num) - 1) >> (PAGE_SHIFT - shift)) + 1;
43
44 if (start < size && size - start >= nr)
45 return 1;
46 WARN(1, "process \"%s\" tried to map%s 0x%08lx-0x%08lx on %s BAR %d "
47 "(size 0x%08lx)\n",
48 current->comm, sparse ? " sparse" : "", start, start + nr,
49 pci_name(pdev), num, size);
50 return 0;
51}
52
53/**
54 * pci_mmap_resource - map a PCI resource into user memory space
55 * @kobj: kobject for mapping
56 * @attr: struct bin_attribute for the file being mapped
57 * @vma: struct vm_area_struct passed into the mmap
58 * @sparse: address space type
59 *
60 * Use the bus mapping routines to map a PCI resource into userspace.
61 */
62static int pci_mmap_resource(struct kobject *kobj, struct bin_attribute *attr,
63 struct vm_area_struct *vma, int sparse)
64{
65 struct pci_dev *pdev = to_pci_dev(container_of(kobj,
66 struct device, kobj));
67 struct resource *res = (struct resource *)attr->private;
68 enum pci_mmap_state mmap_type;
69 struct pci_bus_region bar;
70 int i;
71
72 for (i = 0; i < PCI_ROM_RESOURCE; i++)
73 if (res == &pdev->resource[i])
74 break;
75 if (i >= PCI_ROM_RESOURCE)
76 return -ENODEV;
77
78 if (!__pci_mmap_fits(pdev, i, vma, sparse))
79 return -EINVAL;
80
81 if (iomem_is_exclusive(res->start))
82 return -EINVAL;
83
84 pcibios_resource_to_bus(pdev, &bar, res);
85 vma->vm_pgoff += bar.start >> (PAGE_SHIFT - (sparse ? 5 : 0));
86 mmap_type = res->flags & IORESOURCE_MEM ? pci_mmap_mem : pci_mmap_io;
87
88 return hose_mmap_page_range(pdev->sysdata, vma, mmap_type, sparse);
89}
90
91static int pci_mmap_resource_sparse(struct kobject *kobj,
92 struct bin_attribute *attr,
93 struct vm_area_struct *vma)
94{
95 return pci_mmap_resource(kobj, attr, vma, 1);
96}
97
98static int pci_mmap_resource_dense(struct kobject *kobj,
99 struct bin_attribute *attr,
100 struct vm_area_struct *vma)
101{
102 return pci_mmap_resource(kobj, attr, vma, 0);
103}
104
105/**
106 * pci_remove_resource_files - cleanup resource files
107 * @dev: dev to cleanup
108 *
109 * If we created resource files for @dev, remove them from sysfs and
110 * free their resources.
111 */
112void pci_remove_resource_files(struct pci_dev *pdev)
113{
114 int i;
115
116 for (i = 0; i < PCI_ROM_RESOURCE; i++) {
117 struct bin_attribute *res_attr;
118
119 res_attr = pdev->res_attr[i];
120 if (res_attr) {
121 sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
122 kfree(res_attr);
123 }
124
125 res_attr = pdev->res_attr_wc[i];
126 if (res_attr) {
127 sysfs_remove_bin_file(&pdev->dev.kobj, res_attr);
128 kfree(res_attr);
129 }
130 }
131}
132
133static int sparse_mem_mmap_fits(struct pci_dev *pdev, int num)
134{
135 struct pci_bus_region bar;
136 struct pci_controller *hose = pdev->sysdata;
137 long dense_offset;
138 unsigned long sparse_size;
139
140 pcibios_resource_to_bus(pdev, &bar, &pdev->resource[num]);
141
142 /* All core logic chips have 4G sparse address space, except
143 CIA which has 16G (see xxx_SPARSE_MEM and xxx_DENSE_MEM
144 definitions in asm/core_xxx.h files). This corresponds
145 to 128M or 512M of the bus space. */
146 dense_offset = (long)(hose->dense_mem_base - hose->sparse_mem_base);
147 sparse_size = dense_offset >= 0x400000000UL ? 0x20000000 : 0x8000000;
148
149 return bar.end < sparse_size;
150}
151
152static int pci_create_one_attr(struct pci_dev *pdev, int num, char *name,
153 char *suffix, struct bin_attribute *res_attr,
154 unsigned long sparse)
155{
156 size_t size = pci_resource_len(pdev, num);
157
158 sprintf(name, "resource%d%s", num, suffix);
159 res_attr->mmap = sparse ? pci_mmap_resource_sparse :
160 pci_mmap_resource_dense;
161 res_attr->attr.name = name;
162 res_attr->attr.mode = S_IRUSR | S_IWUSR;
163 res_attr->size = sparse ? size << 5 : size;
164 res_attr->private = &pdev->resource[num];
165 return sysfs_create_bin_file(&pdev->dev.kobj, res_attr);
166}
167
168static int pci_create_attr(struct pci_dev *pdev, int num)
169{
170 /* allocate attribute structure, piggyback attribute name */
171 int retval, nlen1, nlen2 = 0, res_count = 1;
172 unsigned long sparse_base, dense_base;
173 struct bin_attribute *attr;
174 struct pci_controller *hose = pdev->sysdata;
175 char *suffix, *attr_name;
176
177 suffix = ""; /* Assume bwx machine, normal resourceN files. */
178 nlen1 = 10;
179
180 if (pdev->resource[num].flags & IORESOURCE_MEM) {
181 sparse_base = hose->sparse_mem_base;
182 dense_base = hose->dense_mem_base;
183 if (sparse_base && !sparse_mem_mmap_fits(pdev, num)) {
184 sparse_base = 0;
185 suffix = "_dense";
186 nlen1 = 16; /* resourceN_dense */
187 }
188 } else {
189 sparse_base = hose->sparse_io_base;
190 dense_base = hose->dense_io_base;
191 }
192
193 if (sparse_base) {
194 suffix = "_sparse";
195 nlen1 = 17;
196 if (dense_base) {
197 nlen2 = 16; /* resourceN_dense */
198 res_count = 2;
199 }
200 }
201
202 attr = kzalloc(sizeof(*attr) * res_count + nlen1 + nlen2, GFP_ATOMIC);
203 if (!attr)
204 return -ENOMEM;
205
206 /* Create bwx, sparse or single dense file */
207 attr_name = (char *)(attr + res_count);
208 pdev->res_attr[num] = attr;
209 retval = pci_create_one_attr(pdev, num, attr_name, suffix, attr,
210 sparse_base);
211 if (retval || res_count == 1)
212 return retval;
213
214 /* Create dense file */
215 attr_name += nlen1;
216 attr++;
217 pdev->res_attr_wc[num] = attr;
218 return pci_create_one_attr(pdev, num, attr_name, "_dense", attr, 0);
219}
220
221/**
222 * pci_create_resource_files - create resource files in sysfs for @dev
223 * @dev: dev in question
224 *
225 * Walk the resources in @dev creating files for each resource available.
226 */
227int pci_create_resource_files(struct pci_dev *pdev)
228{
229 int i;
230 int retval;
231
232 /* Expose the PCI resources from this device as files */
233 for (i = 0; i < PCI_ROM_RESOURCE; i++) {
234
235 /* skip empty resources */
236 if (!pci_resource_len(pdev, i))
237 continue;
238
239 retval = pci_create_attr(pdev, i);
240 if (retval) {
241 pci_remove_resource_files(pdev);
242 return retval;
243 }
244 }
245 return 0;
246}
247
248/* Legacy I/O bus mapping stuff. */
249
250static int __legacy_mmap_fits(struct pci_controller *hose,
251 struct vm_area_struct *vma,
252 unsigned long res_size, int sparse)
253{
254 unsigned long nr, start, size;
255
256 nr = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
257 start = vma->vm_pgoff;
258 size = ((res_size - 1) >> PAGE_SHIFT) + 1;
259
260 if (start < size && size - start >= nr)
261 return 1;
262 WARN(1, "process \"%s\" tried to map%s 0x%08lx-0x%08lx on hose %d "
263 "(size 0x%08lx)\n",
264 current->comm, sparse ? " sparse" : "", start, start + nr,
265 hose->index, size);
266 return 0;
267}
268
269static inline int has_sparse(struct pci_controller *hose,
270 enum pci_mmap_state mmap_type)
271{
272 unsigned long base;
273
274 base = (mmap_type == pci_mmap_mem) ? hose->sparse_mem_base :
275 hose->sparse_io_base;
276
277 return base != 0;
278}
279
280int pci_mmap_legacy_page_range(struct pci_bus *bus, struct vm_area_struct *vma,
281 enum pci_mmap_state mmap_type)
282{
283 struct pci_controller *hose = bus->sysdata;
284 int sparse = has_sparse(hose, mmap_type);
285 unsigned long res_size;
286
287 res_size = (mmap_type == pci_mmap_mem) ? bus->legacy_mem->size :
288 bus->legacy_io->size;
289 if (!__legacy_mmap_fits(hose, vma, res_size, sparse))
290 return -EINVAL;
291
292 return hose_mmap_page_range(hose, vma, mmap_type, sparse);
293}
294
295/**
296 * pci_adjust_legacy_attr - adjustment of legacy file attributes
297 * @b: bus to create files under
298 * @mmap_type: I/O port or memory
299 *
300 * Adjust file name and size for sparse mappings.
301 */
302void pci_adjust_legacy_attr(struct pci_bus *bus, enum pci_mmap_state mmap_type)
303{
304 struct pci_controller *hose = bus->sysdata;
305
306 if (!has_sparse(hose, mmap_type))
307 return;
308
309 if (mmap_type == pci_mmap_mem) {
310 bus->legacy_mem->attr.name = "legacy_mem_sparse";
311 bus->legacy_mem->size <<= 5;
312 } else {
313 bus->legacy_io->attr.name = "legacy_io_sparse";
314 bus->legacy_io->size <<= 5;
315 }
316 return;
317}
318
319/* Legacy I/O bus read/write functions */
320int pci_legacy_read(struct pci_bus *bus, loff_t port, u32 *val, size_t size)
321{
322 struct pci_controller *hose = bus->sysdata;
323
324 port += hose->io_space->start;
325
326 switch(size) {
327 case 1:
328 *((u8 *)val) = inb(port);
329 return 1;
330 case 2:
331 if (port & 1)
332 return -EINVAL;
333 *((u16 *)val) = inw(port);
334 return 2;
335 case 4:
336 if (port & 3)
337 return -EINVAL;
338 *((u32 *)val) = inl(port);
339 return 4;
340 }
341 return -EINVAL;
342}
343
344int pci_legacy_write(struct pci_bus *bus, loff_t port, u32 val, size_t size)
345{
346 struct pci_controller *hose = bus->sysdata;
347
348 port += hose->io_space->start;
349
350 switch(size) {
351 case 1:
352 outb(port, val);
353 return 1;
354 case 2:
355 if (port & 1)
356 return -EINVAL;
357 outw(port, val);
358 return 2;
359 case 4:
360 if (port & 3)
361 return -EINVAL;
362 outl(port, val);
363 return 4;
364 }
365 return -EINVAL;
366}
diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
index 3548159a1be..ba17d5d90a4 100644
--- a/arch/powerpc/include/asm/pci.h
+++ b/arch/powerpc/include/asm/pci.h
@@ -114,6 +114,10 @@ extern int pci_domain_nr(struct pci_bus *bus);
114/* Decide whether to display the domain number in /proc */ 114/* Decide whether to display the domain number in /proc */
115extern int pci_proc_domain(struct pci_bus *bus); 115extern int pci_proc_domain(struct pci_bus *bus);
116 116
117/* MSI arch hooks */
118#define arch_setup_msi_irqs arch_setup_msi_irqs
119#define arch_teardown_msi_irqs arch_teardown_msi_irqs
120#define arch_msi_check_device arch_msi_check_device
117 121
118struct vm_area_struct; 122struct vm_area_struct;
119/* Map a range of PCI memory or I/O space for a device into user space */ 123/* Map a range of PCI memory or I/O space for a device into user space */
diff --git a/arch/powerpc/kernel/msi.c b/arch/powerpc/kernel/msi.c
index 3bb7d3dd28b..8bbc12d20f5 100644
--- a/arch/powerpc/kernel/msi.c
+++ b/arch/powerpc/kernel/msi.c
@@ -9,6 +9,7 @@
9 9
10#include <linux/kernel.h> 10#include <linux/kernel.h>
11#include <linux/msi.h> 11#include <linux/msi.h>
12#include <linux/pci.h>
12 13
13#include <asm/machdep.h> 14#include <asm/machdep.h>
14 15
@@ -19,6 +20,10 @@ int arch_msi_check_device(struct pci_dev* dev, int nvec, int type)
19 return -ENOSYS; 20 return -ENOSYS;
20 } 21 }
21 22
23 /* PowerPC doesn't support multiple MSI yet */
24 if (type == PCI_CAP_ID_MSI && nvec > 1)
25 return 1;
26
22 if (ppc_md.msi_check_device) { 27 if (ppc_md.msi_check_device) {
23 pr_debug("msi: Using platform check routine.\n"); 28 pr_debug("msi: Using platform check routine.\n");
24 return ppc_md.msi_check_device(dev, nvec, type); 29 return ppc_md.msi_check_device(dev, nvec, type);
diff --git a/arch/x86/include/asm/pci.h b/arch/x86/include/asm/pci.h
index a977de23cb4..a0301bfeb95 100644
--- a/arch/x86/include/asm/pci.h
+++ b/arch/x86/include/asm/pci.h
@@ -86,6 +86,9 @@ static inline void early_quirks(void) { }
86 86
87extern void pci_iommu_alloc(void); 87extern void pci_iommu_alloc(void);
88 88
89/* MSI arch hook */
90#define arch_setup_msi_irqs arch_setup_msi_irqs
91
89#endif /* __KERNEL__ */ 92#endif /* __KERNEL__ */
90 93
91#ifdef CONFIG_X86_32 94#ifdef CONFIG_X86_32
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index da99ffcdfde..1bb5c6cee3e 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -3468,6 +3468,10 @@ int arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
3468 struct intel_iommu *iommu = NULL; 3468 struct intel_iommu *iommu = NULL;
3469 int index = 0; 3469 int index = 0;
3470 3470
3471 /* x86 doesn't support multiple MSI yet */
3472 if (type == PCI_CAP_ID_MSI && nvec > 1)
3473 return 1;
3474
3471 irq_want = nr_irqs_gsi; 3475 irq_want = nr_irqs_gsi;
3472 sub_handle = 0; 3476 sub_handle = 0;
3473 list_for_each_entry(msidesc, &dev->msi_list, list) { 3477 list_for_each_entry(msidesc, &dev->msi_list, list) {
diff --git a/arch/x86/kernel/pci-dma.c b/arch/x86/kernel/pci-dma.c
index c7c4776ff63..90f5b9ef5de 100644
--- a/arch/x86/kernel/pci-dma.c
+++ b/arch/x86/kernel/pci-dma.c
@@ -300,8 +300,7 @@ fs_initcall(pci_iommu_init);
300static __devinit void via_no_dac(struct pci_dev *dev) 300static __devinit void via_no_dac(struct pci_dev *dev)
301{ 301{
302 if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && forbid_dac == 0) { 302 if ((dev->class >> 8) == PCI_CLASS_BRIDGE_PCI && forbid_dac == 0) {
303 printk(KERN_INFO 303 dev_info(&dev->dev, "disabling DAC on VIA PCI bridge\n");
304 "PCI: VIA PCI bridge detected. Disabling DAC.\n");
305 forbid_dac = 1; 304 forbid_dac = 1;
306 } 305 }
307} 306}
diff --git a/arch/x86/pci/early.c b/arch/x86/pci/early.c
index f6adf2c6d75..aaf26ae58cd 100644
--- a/arch/x86/pci/early.c
+++ b/arch/x86/pci/early.c
@@ -69,11 +69,12 @@ void early_dump_pci_device(u8 bus, u8 slot, u8 func)
69 int j; 69 int j;
70 u32 val; 70 u32 val;
71 71
72 printk(KERN_INFO "PCI: %02x:%02x:%02x", bus, slot, func); 72 printk(KERN_INFO "pci 0000:%02x:%02x.%d config space:",
73 bus, slot, func);
73 74
74 for (i = 0; i < 256; i += 4) { 75 for (i = 0; i < 256; i += 4) {
75 if (!(i & 0x0f)) 76 if (!(i & 0x0f))
76 printk("\n%04x:",i); 77 printk("\n %02x:",i);
77 78
78 val = read_pci_config(bus, slot, func, i); 79 val = read_pci_config(bus, slot, func, i);
79 for (j = 0; j < 4; j++) { 80 for (j = 0; j < 4; j++) {
@@ -96,20 +97,22 @@ void early_dump_pci_devices(void)
96 for (func = 0; func < 8; func++) { 97 for (func = 0; func < 8; func++) {
97 u32 class; 98 u32 class;
98 u8 type; 99 u8 type;
100
99 class = read_pci_config(bus, slot, func, 101 class = read_pci_config(bus, slot, func,
100 PCI_CLASS_REVISION); 102 PCI_CLASS_REVISION);
101 if (class == 0xffffffff) 103 if (class == 0xffffffff)
102 break; 104 continue;
103 105
104 early_dump_pci_device(bus, slot, func); 106 early_dump_pci_device(bus, slot, func);
105 107
106 /* No multi-function device? */ 108 if (func == 0) {
107 type = read_pci_config_byte(bus, slot, func, 109 type = read_pci_config_byte(bus, slot,
110 func,
108 PCI_HEADER_TYPE); 111 PCI_HEADER_TYPE);
109 if (!(type & 0x80)) 112 if (!(type & 0x80))
110 break; 113 break;
114 }
111 } 115 }
112 } 116 }
113 } 117 }
114} 118}
115
diff --git a/arch/x86/pci/fixup.c b/arch/x86/pci/fixup.c
index 9c49919e4d1..6dd89555fbf 100644
--- a/arch/x86/pci/fixup.c
+++ b/arch/x86/pci/fixup.c
@@ -495,26 +495,6 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SIEMENS, 0x0015,
495 pci_siemens_interrupt_controller); 495 pci_siemens_interrupt_controller);
496 496
497/* 497/*
498 * Regular PCI devices have 256 bytes, but AMD Family 10h/11h CPUs have
499 * 4096 bytes configuration space for each function of their processor
500 * configuration space.
501 */
502static void amd_cpu_pci_cfg_space_size(struct pci_dev *dev)
503{
504 dev->cfg_size = pci_cfg_space_size_ext(dev);
505}
506DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1200, amd_cpu_pci_cfg_space_size);
507DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1201, amd_cpu_pci_cfg_space_size);
508DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1202, amd_cpu_pci_cfg_space_size);
509DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1203, amd_cpu_pci_cfg_space_size);
510DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1204, amd_cpu_pci_cfg_space_size);
511DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1300, amd_cpu_pci_cfg_space_size);
512DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1301, amd_cpu_pci_cfg_space_size);
513DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1302, amd_cpu_pci_cfg_space_size);
514DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1303, amd_cpu_pci_cfg_space_size);
515DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, 0x1304, amd_cpu_pci_cfg_space_size);
516
517/*
518 * SB600: Disable BAR1 on device 14.0 to avoid HPET resources from 498 * SB600: Disable BAR1 on device 14.0 to avoid HPET resources from
519 * confusing the PCI engine: 499 * confusing the PCI engine:
520 */ 500 */
diff --git a/arch/x86/pci/legacy.c b/arch/x86/pci/legacy.c
index f1065b129e9..4061bb0f267 100644
--- a/arch/x86/pci/legacy.c
+++ b/arch/x86/pci/legacy.c
@@ -50,8 +50,6 @@ static int __init pci_legacy_init(void)
50 if (pci_root_bus) 50 if (pci_root_bus)
51 pci_bus_add_devices(pci_root_bus); 51 pci_bus_add_devices(pci_root_bus);
52 52
53 pcibios_fixup_peer_bridges();
54
55 return 0; 53 return 0;
56} 54}
57 55
@@ -67,6 +65,7 @@ int __init pci_subsys_init(void)
67 pci_visws_init(); 65 pci_visws_init();
68#endif 66#endif
69 pci_legacy_init(); 67 pci_legacy_init();
68 pcibios_fixup_peer_bridges();
70 pcibios_irq_init(); 69 pcibios_irq_init();
71 pcibios_init(); 70 pcibios_init();
72 71
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c
index 89bf9242c80..905bb526b13 100644
--- a/arch/x86/pci/mmconfig-shared.c
+++ b/arch/x86/pci/mmconfig-shared.c
@@ -14,6 +14,7 @@
14#include <linux/init.h> 14#include <linux/init.h>
15#include <linux/acpi.h> 15#include <linux/acpi.h>
16#include <linux/bitmap.h> 16#include <linux/bitmap.h>
17#include <linux/sort.h>
17#include <asm/e820.h> 18#include <asm/e820.h>
18#include <asm/pci_x86.h> 19#include <asm/pci_x86.h>
19 20
@@ -24,24 +25,49 @@
24/* Indicate if the mmcfg resources have been placed into the resource table. */ 25/* Indicate if the mmcfg resources have been placed into the resource table. */
25static int __initdata pci_mmcfg_resources_inserted; 26static int __initdata pci_mmcfg_resources_inserted;
26 27
28static __init int extend_mmcfg(int num)
29{
30 struct acpi_mcfg_allocation *new;
31 int new_num = pci_mmcfg_config_num + num;
32
33 new = kzalloc(sizeof(pci_mmcfg_config[0]) * new_num, GFP_KERNEL);
34 if (!new)
35 return -1;
36
37 if (pci_mmcfg_config) {
38 memcpy(new, pci_mmcfg_config,
39 sizeof(pci_mmcfg_config[0]) * new_num);
40 kfree(pci_mmcfg_config);
41 }
42 pci_mmcfg_config = new;
43
44 return 0;
45}
46
47static __init void fill_one_mmcfg(u64 addr, int segment, int start, int end)
48{
49 int i = pci_mmcfg_config_num;
50
51 pci_mmcfg_config_num++;
52 pci_mmcfg_config[i].address = addr;
53 pci_mmcfg_config[i].pci_segment = segment;
54 pci_mmcfg_config[i].start_bus_number = start;
55 pci_mmcfg_config[i].end_bus_number = end;
56}
57
27static const char __init *pci_mmcfg_e7520(void) 58static const char __init *pci_mmcfg_e7520(void)
28{ 59{
29 u32 win; 60 u32 win;
30 raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0xce, 2, &win); 61 raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0xce, 2, &win);
31 62
32 win = win & 0xf000; 63 win = win & 0xf000;
33 if(win == 0x0000 || win == 0xf000) 64 if (win == 0x0000 || win == 0xf000)
34 pci_mmcfg_config_num = 0; 65 return NULL;
35 else { 66
36 pci_mmcfg_config_num = 1; 67 if (extend_mmcfg(1) == -1)
37 pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL); 68 return NULL;
38 if (!pci_mmcfg_config) 69
39 return NULL; 70 fill_one_mmcfg(win << 16, 0, 0, 255);
40 pci_mmcfg_config[0].address = win << 16;
41 pci_mmcfg_config[0].pci_segment = 0;
42 pci_mmcfg_config[0].start_bus_number = 0;
43 pci_mmcfg_config[0].end_bus_number = 255;
44 }
45 71
46 return "Intel Corporation E7520 Memory Controller Hub"; 72 return "Intel Corporation E7520 Memory Controller Hub";
47} 73}
@@ -50,13 +76,11 @@ static const char __init *pci_mmcfg_intel_945(void)
50{ 76{
51 u32 pciexbar, mask = 0, len = 0; 77 u32 pciexbar, mask = 0, len = 0;
52 78
53 pci_mmcfg_config_num = 1;
54
55 raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0x48, 4, &pciexbar); 79 raw_pci_ops->read(0, 0, PCI_DEVFN(0, 0), 0x48, 4, &pciexbar);
56 80
57 /* Enable bit */ 81 /* Enable bit */
58 if (!(pciexbar & 1)) 82 if (!(pciexbar & 1))
59 pci_mmcfg_config_num = 0; 83 return NULL;
60 84
61 /* Size bits */ 85 /* Size bits */
62 switch ((pciexbar >> 1) & 3) { 86 switch ((pciexbar >> 1) & 3) {
@@ -73,28 +97,23 @@ static const char __init *pci_mmcfg_intel_945(void)
73 len = 0x04000000U; 97 len = 0x04000000U;
74 break; 98 break;
75 default: 99 default:
76 pci_mmcfg_config_num = 0; 100 return NULL;
77 } 101 }
78 102
79 /* Errata #2, things break when not aligned on a 256Mb boundary */ 103 /* Errata #2, things break when not aligned on a 256Mb boundary */
80 /* Can only happen in 64M/128M mode */ 104 /* Can only happen in 64M/128M mode */
81 105
82 if ((pciexbar & mask) & 0x0fffffffU) 106 if ((pciexbar & mask) & 0x0fffffffU)
83 pci_mmcfg_config_num = 0; 107 return NULL;
84 108
85 /* Don't hit the APIC registers and their friends */ 109 /* Don't hit the APIC registers and their friends */
86 if ((pciexbar & mask) >= 0xf0000000U) 110 if ((pciexbar & mask) >= 0xf0000000U)
87 pci_mmcfg_config_num = 0; 111 return NULL;
88 112
89 if (pci_mmcfg_config_num) { 113 if (extend_mmcfg(1) == -1)
90 pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]), GFP_KERNEL); 114 return NULL;
91 if (!pci_mmcfg_config) 115
92 return NULL; 116 fill_one_mmcfg(pciexbar & mask, 0, 0, (len >> 20) - 1);
93 pci_mmcfg_config[0].address = pciexbar & mask;
94 pci_mmcfg_config[0].pci_segment = 0;
95 pci_mmcfg_config[0].start_bus_number = 0;
96 pci_mmcfg_config[0].end_bus_number = (len >> 20) - 1;
97 }
98 117
99 return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub"; 118 return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub";
100} 119}
@@ -138,22 +157,77 @@ static const char __init *pci_mmcfg_amd_fam10h(void)
138 busnbits = 8; 157 busnbits = 8;
139 } 158 }
140 159
141 pci_mmcfg_config_num = (1 << segnbits); 160 if (extend_mmcfg(1 << segnbits) == -1)
142 pci_mmcfg_config = kzalloc(sizeof(pci_mmcfg_config[0]) *
143 pci_mmcfg_config_num, GFP_KERNEL);
144 if (!pci_mmcfg_config)
145 return NULL; 161 return NULL;
146 162
147 for (i = 0; i < (1 << segnbits); i++) { 163 for (i = 0; i < (1 << segnbits); i++)
148 pci_mmcfg_config[i].address = base + (1<<28) * i; 164 fill_one_mmcfg(base + (1<<28) * i, i, 0, (1 << busnbits) - 1);
149 pci_mmcfg_config[i].pci_segment = i;
150 pci_mmcfg_config[i].start_bus_number = 0;
151 pci_mmcfg_config[i].end_bus_number = (1 << busnbits) - 1;
152 }
153 165
154 return "AMD Family 10h NB"; 166 return "AMD Family 10h NB";
155} 167}
156 168
169static bool __initdata mcp55_checked;
170static const char __init *pci_mmcfg_nvidia_mcp55(void)
171{
172 int bus;
173 int mcp55_mmconf_found = 0;
174
175 static const u32 extcfg_regnum = 0x90;
176 static const u32 extcfg_regsize = 4;
177 static const u32 extcfg_enable_mask = 1<<31;
178 static const u32 extcfg_start_mask = 0xff<<16;
179 static const int extcfg_start_shift = 16;
180 static const u32 extcfg_size_mask = 0x3<<28;
181 static const int extcfg_size_shift = 28;
182 static const int extcfg_sizebus[] = {0x100, 0x80, 0x40, 0x20};
183 static const u32 extcfg_base_mask[] = {0x7ff8, 0x7ffc, 0x7ffe, 0x7fff};
184 static const int extcfg_base_lshift = 25;
185
186 /*
187 * do check if amd fam10h already took over
188 */
189 if (!acpi_disabled || pci_mmcfg_config_num || mcp55_checked)
190 return NULL;
191
192 mcp55_checked = true;
193 for (bus = 0; bus < 256; bus++) {
194 u64 base;
195 u32 l, extcfg;
196 u16 vendor, device;
197 int start, size_index, end;
198
199 raw_pci_ops->read(0, bus, PCI_DEVFN(0, 0), 0, 4, &l);
200 vendor = l & 0xffff;
201 device = (l >> 16) & 0xffff;
202
203 if (PCI_VENDOR_ID_NVIDIA != vendor || 0x0369 != device)
204 continue;
205
206 raw_pci_ops->read(0, bus, PCI_DEVFN(0, 0), extcfg_regnum,
207 extcfg_regsize, &extcfg);
208
209 if (!(extcfg & extcfg_enable_mask))
210 continue;
211
212 if (extend_mmcfg(1) == -1)
213 continue;
214
215 size_index = (extcfg & extcfg_size_mask) >> extcfg_size_shift;
216 base = extcfg & extcfg_base_mask[size_index];
217 /* base could > 4G */
218 base <<= extcfg_base_lshift;
219 start = (extcfg & extcfg_start_mask) >> extcfg_start_shift;
220 end = start + extcfg_sizebus[size_index] - 1;
221 fill_one_mmcfg(base, 0, start, end);
222 mcp55_mmconf_found++;
223 }
224
225 if (!mcp55_mmconf_found)
226 return NULL;
227
228 return "nVidia MCP55";
229}
230
157struct pci_mmcfg_hostbridge_probe { 231struct pci_mmcfg_hostbridge_probe {
158 u32 bus; 232 u32 bus;
159 u32 devfn; 233 u32 devfn;
@@ -171,8 +245,52 @@ static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = {
171 0x1200, pci_mmcfg_amd_fam10h }, 245 0x1200, pci_mmcfg_amd_fam10h },
172 { 0xff, PCI_DEVFN(0, 0), PCI_VENDOR_ID_AMD, 246 { 0xff, PCI_DEVFN(0, 0), PCI_VENDOR_ID_AMD,
173 0x1200, pci_mmcfg_amd_fam10h }, 247 0x1200, pci_mmcfg_amd_fam10h },
248 { 0, PCI_DEVFN(0, 0), PCI_VENDOR_ID_NVIDIA,
249 0x0369, pci_mmcfg_nvidia_mcp55 },
174}; 250};
175 251
252static int __init cmp_mmcfg(const void *x1, const void *x2)
253{
254 const typeof(pci_mmcfg_config[0]) *m1 = x1;
255 const typeof(pci_mmcfg_config[0]) *m2 = x2;
256 int start1, start2;
257
258 start1 = m1->start_bus_number;
259 start2 = m2->start_bus_number;
260
261 return start1 - start2;
262}
263
264static void __init pci_mmcfg_check_end_bus_number(void)
265{
266 int i;
267 typeof(pci_mmcfg_config[0]) *cfg, *cfgx;
268
269 /* sort them at first */
270 sort(pci_mmcfg_config, pci_mmcfg_config_num,
271 sizeof(pci_mmcfg_config[0]), cmp_mmcfg, NULL);
272
273 /* last one*/
274 if (pci_mmcfg_config_num > 0) {
275 i = pci_mmcfg_config_num - 1;
276 cfg = &pci_mmcfg_config[i];
277 if (cfg->end_bus_number < cfg->start_bus_number)
278 cfg->end_bus_number = 255;
279 }
280
281 /* don't overlap please */
282 for (i = 0; i < pci_mmcfg_config_num - 1; i++) {
283 cfg = &pci_mmcfg_config[i];
284 cfgx = &pci_mmcfg_config[i+1];
285
286 if (cfg->end_bus_number < cfg->start_bus_number)
287 cfg->end_bus_number = 255;
288
289 if (cfg->end_bus_number >= cfgx->start_bus_number)
290 cfg->end_bus_number = cfgx->start_bus_number - 1;
291 }
292}
293
176static int __init pci_mmcfg_check_hostbridge(void) 294static int __init pci_mmcfg_check_hostbridge(void)
177{ 295{
178 u32 l; 296 u32 l;
@@ -186,31 +304,33 @@ static int __init pci_mmcfg_check_hostbridge(void)
186 304
187 pci_mmcfg_config_num = 0; 305 pci_mmcfg_config_num = 0;
188 pci_mmcfg_config = NULL; 306 pci_mmcfg_config = NULL;
189 name = NULL;
190 307
191 for (i = 0; !name && i < ARRAY_SIZE(pci_mmcfg_probes); i++) { 308 for (i = 0; i < ARRAY_SIZE(pci_mmcfg_probes); i++) {
192 bus = pci_mmcfg_probes[i].bus; 309 bus = pci_mmcfg_probes[i].bus;
193 devfn = pci_mmcfg_probes[i].devfn; 310 devfn = pci_mmcfg_probes[i].devfn;
194 raw_pci_ops->read(0, bus, devfn, 0, 4, &l); 311 raw_pci_ops->read(0, bus, devfn, 0, 4, &l);
195 vendor = l & 0xffff; 312 vendor = l & 0xffff;
196 device = (l >> 16) & 0xffff; 313 device = (l >> 16) & 0xffff;
197 314
315 name = NULL;
198 if (pci_mmcfg_probes[i].vendor == vendor && 316 if (pci_mmcfg_probes[i].vendor == vendor &&
199 pci_mmcfg_probes[i].device == device) 317 pci_mmcfg_probes[i].device == device)
200 name = pci_mmcfg_probes[i].probe(); 318 name = pci_mmcfg_probes[i].probe();
201 }
202 319
203 if (name) { 320 if (name)
204 printk(KERN_INFO "PCI: Found %s %s MMCONFIG support.\n", 321 printk(KERN_INFO "PCI: Found %s with MMCONFIG support.\n",
205 name, pci_mmcfg_config_num ? "with" : "without"); 322 name);
206 } 323 }
207 324
208 return name != NULL; 325 /* some end_bus_number is crazy, fix it */
326 pci_mmcfg_check_end_bus_number();
327
328 return pci_mmcfg_config_num != 0;
209} 329}
210 330
211static void __init pci_mmcfg_insert_resources(void) 331static void __init pci_mmcfg_insert_resources(void)
212{ 332{
213#define PCI_MMCFG_RESOURCE_NAME_LEN 19 333#define PCI_MMCFG_RESOURCE_NAME_LEN 24
214 int i; 334 int i;
215 struct resource *res; 335 struct resource *res;
216 char *names; 336 char *names;
@@ -228,9 +348,10 @@ static void __init pci_mmcfg_insert_resources(void)
228 struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[i]; 348 struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[i];
229 num_buses = cfg->end_bus_number - cfg->start_bus_number + 1; 349 num_buses = cfg->end_bus_number - cfg->start_bus_number + 1;
230 res->name = names; 350 res->name = names;
231 snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN, "PCI MMCONFIG %u", 351 snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN,
232 cfg->pci_segment); 352 "PCI MMCONFIG %u [%02x-%02x]", cfg->pci_segment,
233 res->start = cfg->address; 353 cfg->start_bus_number, cfg->end_bus_number);
354 res->start = cfg->address + (cfg->start_bus_number << 20);
234 res->end = res->start + (num_buses << 20) - 1; 355 res->end = res->start + (num_buses << 20) - 1;
235 res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; 356 res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
236 insert_resource(&iomem_resource, res); 357 insert_resource(&iomem_resource, res);
@@ -354,8 +475,6 @@ static void __init pci_mmcfg_reject_broken(int early)
354 (pci_mmcfg_config[0].address == 0)) 475 (pci_mmcfg_config[0].address == 0))
355 return; 476 return;
356 477
357 cfg = &pci_mmcfg_config[0];
358
359 for (i = 0; i < pci_mmcfg_config_num; i++) { 478 for (i = 0; i < pci_mmcfg_config_num; i++) {
360 int valid = 0; 479 int valid = 0;
361 u64 addr, size; 480 u64 addr, size;
@@ -423,10 +542,10 @@ static void __init __pci_mmcfg_init(int early)
423 known_bridge = 1; 542 known_bridge = 1;
424 } 543 }
425 544
426 if (!known_bridge) { 545 if (!known_bridge)
427 acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg); 546 acpi_table_parse(ACPI_SIG_MCFG, acpi_parse_mcfg);
428 pci_mmcfg_reject_broken(early); 547
429 } 548 pci_mmcfg_reject_broken(early);
430 549
431 if ((pci_mmcfg_config_num == 0) || 550 if ((pci_mmcfg_config_num == 0) ||
432 (pci_mmcfg_config == NULL) || 551 (pci_mmcfg_config == NULL) ||
diff --git a/arch/x86/pci/mmconfig_64.c b/arch/x86/pci/mmconfig_64.c
index 30007ffc8e1..94349f8b2f9 100644
--- a/arch/x86/pci/mmconfig_64.c
+++ b/arch/x86/pci/mmconfig_64.c
@@ -112,13 +112,18 @@ static struct pci_raw_ops pci_mmcfg = {
112static void __iomem * __init mcfg_ioremap(struct acpi_mcfg_allocation *cfg) 112static void __iomem * __init mcfg_ioremap(struct acpi_mcfg_allocation *cfg)
113{ 113{
114 void __iomem *addr; 114 void __iomem *addr;
115 u32 size; 115 u64 start, size;
116 116
117 size = (cfg->end_bus_number + 1) << 20; 117 start = cfg->start_bus_number;
118 addr = ioremap_nocache(cfg->address, size); 118 start <<= 20;
119 start += cfg->address;
120 size = cfg->end_bus_number + 1 - cfg->start_bus_number;
121 size <<= 20;
122 addr = ioremap_nocache(start, size);
119 if (addr) { 123 if (addr) {
120 printk(KERN_INFO "PCI: Using MMCONFIG at %Lx - %Lx\n", 124 printk(KERN_INFO "PCI: Using MMCONFIG at %Lx - %Lx\n",
121 cfg->address, cfg->address + size - 1); 125 start, start + size - 1);
126 addr -= cfg->start_bus_number << 20;
122 } 127 }
123 return addr; 128 return addr;
124} 129}
@@ -157,7 +162,7 @@ void __init pci_mmcfg_arch_free(void)
157 162
158 for (i = 0; i < pci_mmcfg_config_num; ++i) { 163 for (i = 0; i < pci_mmcfg_config_num; ++i) {
159 if (pci_mmcfg_virt[i].virt) { 164 if (pci_mmcfg_virt[i].virt) {
160 iounmap(pci_mmcfg_virt[i].virt); 165 iounmap(pci_mmcfg_virt[i].virt + (pci_mmcfg_virt[i].cfg->start_bus_number << 20));
161 pci_mmcfg_virt[i].virt = NULL; 166 pci_mmcfg_virt[i].virt = NULL;
162 pci_mmcfg_virt[i].cfg = NULL; 167 pci_mmcfg_virt[i].cfg = NULL;
163 } 168 }