diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /arch/x86/pci | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'arch/x86/pci')
-rw-r--r-- | arch/x86/pci/Makefile | 8 | ||||
-rw-r--r-- | arch/x86/pci/acpi.c | 170 | ||||
-rw-r--r-- | arch/x86/pci/amd_bus.c | 239 | ||||
-rw-r--r-- | arch/x86/pci/bus_numa.c | 101 | ||||
-rw-r--r-- | arch/x86/pci/bus_numa.h | 25 | ||||
-rw-r--r-- | arch/x86/pci/common.c | 30 | ||||
-rw-r--r-- | arch/x86/pci/early.c | 7 | ||||
-rw-r--r-- | arch/x86/pci/i386.c | 58 | ||||
-rw-r--r-- | arch/x86/pci/init.c | 8 | ||||
-rw-r--r-- | arch/x86/pci/irq.c | 19 | ||||
-rw-r--r-- | arch/x86/pci/legacy.c | 24 | ||||
-rw-r--r-- | arch/x86/pci/mmconfig-shared.c | 356 | ||||
-rw-r--r-- | arch/x86/pci/mmconfig_32.c | 16 | ||||
-rw-r--r-- | arch/x86/pci/mmconfig_64.c | 88 | ||||
-rw-r--r-- | arch/x86/pci/mrst.c | 266 | ||||
-rw-r--r-- | arch/x86/pci/numaq_32.c | 12 | ||||
-rw-r--r-- | arch/x86/pci/olpc.c | 3 | ||||
-rw-r--r-- | arch/x86/pci/pcbios.c | 1 | ||||
-rw-r--r-- | arch/x86/pci/visws.c | 6 |
19 files changed, 831 insertions, 606 deletions
diff --git a/arch/x86/pci/Makefile b/arch/x86/pci/Makefile index d49202e740ea..b110d97fb925 100644 --- a/arch/x86/pci/Makefile +++ b/arch/x86/pci/Makefile | |||
@@ -13,5 +13,11 @@ obj-$(CONFIG_X86_VISWS) += visws.o | |||
13 | 13 | ||
14 | obj-$(CONFIG_X86_NUMAQ) += numaq_32.o | 14 | obj-$(CONFIG_X86_NUMAQ) += numaq_32.o |
15 | 15 | ||
16 | obj-$(CONFIG_X86_MRST) += mrst.o | ||
17 | |||
16 | obj-y += common.o early.o | 18 | obj-y += common.o early.o |
17 | obj-y += amd_bus.o | 19 | obj-y += amd_bus.o bus_numa.o |
20 | |||
21 | ifeq ($(CONFIG_PCI_DEBUG),y) | ||
22 | EXTRA_CFLAGS += -DDEBUG | ||
23 | endif | ||
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index 1014eb4bfc37..31930fd30ea9 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c | |||
@@ -3,10 +3,12 @@ | |||
3 | #include <linux/init.h> | 3 | #include <linux/init.h> |
4 | #include <linux/irq.h> | 4 | #include <linux/irq.h> |
5 | #include <linux/dmi.h> | 5 | #include <linux/dmi.h> |
6 | #include <linux/slab.h> | ||
6 | #include <asm/numa.h> | 7 | #include <asm/numa.h> |
7 | #include <asm/pci_x86.h> | 8 | #include <asm/pci_x86.h> |
8 | 9 | ||
9 | struct pci_root_info { | 10 | struct pci_root_info { |
11 | struct acpi_device *bridge; | ||
10 | char *name; | 12 | char *name; |
11 | unsigned int res_num; | 13 | unsigned int res_num; |
12 | struct resource *res; | 14 | struct resource *res; |
@@ -14,19 +16,94 @@ struct pci_root_info { | |||
14 | int busnum; | 16 | int busnum; |
15 | }; | 17 | }; |
16 | 18 | ||
19 | static bool pci_use_crs = true; | ||
20 | |||
21 | static int __init set_use_crs(const struct dmi_system_id *id) | ||
22 | { | ||
23 | pci_use_crs = true; | ||
24 | return 0; | ||
25 | } | ||
26 | |||
27 | static const struct dmi_system_id pci_use_crs_table[] __initconst = { | ||
28 | /* http://bugzilla.kernel.org/show_bug.cgi?id=14183 */ | ||
29 | { | ||
30 | .callback = set_use_crs, | ||
31 | .ident = "IBM System x3800", | ||
32 | .matches = { | ||
33 | DMI_MATCH(DMI_SYS_VENDOR, "IBM"), | ||
34 | DMI_MATCH(DMI_PRODUCT_NAME, "x3800"), | ||
35 | }, | ||
36 | }, | ||
37 | {} | ||
38 | }; | ||
39 | |||
40 | void __init pci_acpi_crs_quirks(void) | ||
41 | { | ||
42 | int year; | ||
43 | |||
44 | if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && year < 2008) | ||
45 | pci_use_crs = false; | ||
46 | |||
47 | dmi_check_system(pci_use_crs_table); | ||
48 | |||
49 | /* | ||
50 | * If the user specifies "pci=use_crs" or "pci=nocrs" explicitly, that | ||
51 | * takes precedence over anything we figured out above. | ||
52 | */ | ||
53 | if (pci_probe & PCI_ROOT_NO_CRS) | ||
54 | pci_use_crs = false; | ||
55 | else if (pci_probe & PCI_USE__CRS) | ||
56 | pci_use_crs = true; | ||
57 | |||
58 | printk(KERN_INFO "PCI: %s host bridge windows from ACPI; " | ||
59 | "if necessary, use \"pci=%s\" and report a bug\n", | ||
60 | pci_use_crs ? "Using" : "Ignoring", | ||
61 | pci_use_crs ? "nocrs" : "use_crs"); | ||
62 | } | ||
63 | |||
17 | static acpi_status | 64 | static acpi_status |
18 | resource_to_addr(struct acpi_resource *resource, | 65 | resource_to_addr(struct acpi_resource *resource, |
19 | struct acpi_resource_address64 *addr) | 66 | struct acpi_resource_address64 *addr) |
20 | { | 67 | { |
21 | acpi_status status; | 68 | acpi_status status; |
22 | 69 | struct acpi_resource_memory24 *memory24; | |
23 | status = acpi_resource_to_address64(resource, addr); | 70 | struct acpi_resource_memory32 *memory32; |
24 | if (ACPI_SUCCESS(status) && | 71 | struct acpi_resource_fixed_memory32 *fixed_memory32; |
25 | (addr->resource_type == ACPI_MEMORY_RANGE || | 72 | |
26 | addr->resource_type == ACPI_IO_RANGE) && | 73 | memset(addr, 0, sizeof(*addr)); |
27 | addr->address_length > 0 && | 74 | switch (resource->type) { |
28 | addr->producer_consumer == ACPI_PRODUCER) { | 75 | case ACPI_RESOURCE_TYPE_MEMORY24: |
76 | memory24 = &resource->data.memory24; | ||
77 | addr->resource_type = ACPI_MEMORY_RANGE; | ||
78 | addr->minimum = memory24->minimum; | ||
79 | addr->address_length = memory24->address_length; | ||
80 | addr->maximum = addr->minimum + addr->address_length - 1; | ||
81 | return AE_OK; | ||
82 | case ACPI_RESOURCE_TYPE_MEMORY32: | ||
83 | memory32 = &resource->data.memory32; | ||
84 | addr->resource_type = ACPI_MEMORY_RANGE; | ||
85 | addr->minimum = memory32->minimum; | ||
86 | addr->address_length = memory32->address_length; | ||
87 | addr->maximum = addr->minimum + addr->address_length - 1; | ||
29 | return AE_OK; | 88 | return AE_OK; |
89 | case ACPI_RESOURCE_TYPE_FIXED_MEMORY32: | ||
90 | fixed_memory32 = &resource->data.fixed_memory32; | ||
91 | addr->resource_type = ACPI_MEMORY_RANGE; | ||
92 | addr->minimum = fixed_memory32->address; | ||
93 | addr->address_length = fixed_memory32->address_length; | ||
94 | addr->maximum = addr->minimum + addr->address_length - 1; | ||
95 | return AE_OK; | ||
96 | case ACPI_RESOURCE_TYPE_ADDRESS16: | ||
97 | case ACPI_RESOURCE_TYPE_ADDRESS32: | ||
98 | case ACPI_RESOURCE_TYPE_ADDRESS64: | ||
99 | status = acpi_resource_to_address64(resource, addr); | ||
100 | if (ACPI_SUCCESS(status) && | ||
101 | (addr->resource_type == ACPI_MEMORY_RANGE || | ||
102 | addr->resource_type == ACPI_IO_RANGE) && | ||
103 | addr->address_length > 0) { | ||
104 | return AE_OK; | ||
105 | } | ||
106 | break; | ||
30 | } | 107 | } |
31 | return AE_ERROR; | 108 | return AE_ERROR; |
32 | } | 109 | } |
@@ -44,20 +121,6 @@ count_resource(struct acpi_resource *acpi_res, void *data) | |||
44 | return AE_OK; | 121 | return AE_OK; |
45 | } | 122 | } |
46 | 123 | ||
47 | static int | ||
48 | bus_has_transparent_bridge(struct pci_bus *bus) | ||
49 | { | ||
50 | struct pci_dev *dev; | ||
51 | |||
52 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
53 | u16 class = dev->class >> 8; | ||
54 | |||
55 | if (class == PCI_CLASS_BRIDGE_PCI && dev->transparent) | ||
56 | return true; | ||
57 | } | ||
58 | return false; | ||
59 | } | ||
60 | |||
61 | static acpi_status | 124 | static acpi_status |
62 | setup_resource(struct acpi_resource *acpi_res, void *data) | 125 | setup_resource(struct acpi_resource *acpi_res, void *data) |
63 | { | 126 | { |
@@ -66,13 +129,9 @@ setup_resource(struct acpi_resource *acpi_res, void *data) | |||
66 | struct acpi_resource_address64 addr; | 129 | struct acpi_resource_address64 addr; |
67 | acpi_status status; | 130 | acpi_status status; |
68 | unsigned long flags; | 131 | unsigned long flags; |
69 | struct resource *root; | 132 | struct resource *root, *conflict; |
70 | int max_root_bus_resources = PCI_BUS_NUM_RESOURCES; | ||
71 | u64 start, end; | 133 | u64 start, end; |
72 | 134 | ||
73 | if (bus_has_transparent_bridge(info->bus)) | ||
74 | max_root_bus_resources -= 3; | ||
75 | |||
76 | status = resource_to_addr(acpi_res, &addr); | 135 | status = resource_to_addr(acpi_res, &addr); |
77 | if (!ACPI_SUCCESS(status)) | 136 | if (!ACPI_SUCCESS(status)) |
78 | return AE_OK; | 137 | return AE_OK; |
@@ -89,15 +148,7 @@ setup_resource(struct acpi_resource *acpi_res, void *data) | |||
89 | return AE_OK; | 148 | return AE_OK; |
90 | 149 | ||
91 | start = addr.minimum + addr.translation_offset; | 150 | start = addr.minimum + addr.translation_offset; |
92 | end = start + addr.address_length - 1; | 151 | end = addr.maximum + addr.translation_offset; |
93 | if (info->res_num >= max_root_bus_resources) { | ||
94 | printk(KERN_WARNING "PCI: Failed to allocate 0x%lx-0x%lx " | ||
95 | "from %s for %s due to _CRS returning more than " | ||
96 | "%d resource descriptors\n", (unsigned long) start, | ||
97 | (unsigned long) end, root->name, info->name, | ||
98 | max_root_bus_resources); | ||
99 | return AE_OK; | ||
100 | } | ||
101 | 152 | ||
102 | res = &info->res[info->res_num]; | 153 | res = &info->res[info->res_num]; |
103 | res->name = info->name; | 154 | res->name = info->name; |
@@ -106,13 +157,29 @@ setup_resource(struct acpi_resource *acpi_res, void *data) | |||
106 | res->end = end; | 157 | res->end = end; |
107 | res->child = NULL; | 158 | res->child = NULL; |
108 | 159 | ||
109 | if (insert_resource(root, res)) { | 160 | if (!pci_use_crs) { |
110 | printk(KERN_ERR "PCI: Failed to allocate 0x%lx-0x%lx " | 161 | dev_printk(KERN_DEBUG, &info->bridge->dev, |
111 | "from %s for %s\n", (unsigned long) res->start, | 162 | "host bridge window %pR (ignored)\n", res); |
112 | (unsigned long) res->end, root->name, info->name); | 163 | return AE_OK; |
164 | } | ||
165 | |||
166 | conflict = insert_resource_conflict(root, res); | ||
167 | if (conflict) { | ||
168 | dev_err(&info->bridge->dev, | ||
169 | "address space collision: host bridge window %pR " | ||
170 | "conflicts with %s %pR\n", | ||
171 | res, conflict->name, conflict); | ||
113 | } else { | 172 | } else { |
114 | info->bus->resource[info->res_num] = res; | 173 | pci_bus_add_resource(info->bus, res, 0); |
115 | info->res_num++; | 174 | info->res_num++; |
175 | if (addr.translation_offset) | ||
176 | dev_info(&info->bridge->dev, "host bridge window %pR " | ||
177 | "(PCI address [%#llx-%#llx])\n", | ||
178 | res, res->start - addr.translation_offset, | ||
179 | res->end - addr.translation_offset); | ||
180 | else | ||
181 | dev_info(&info->bridge->dev, | ||
182 | "host bridge window %pR\n", res); | ||
116 | } | 183 | } |
117 | return AE_OK; | 184 | return AE_OK; |
118 | } | 185 | } |
@@ -124,6 +191,10 @@ get_current_resources(struct acpi_device *device, int busnum, | |||
124 | struct pci_root_info info; | 191 | struct pci_root_info info; |
125 | size_t size; | 192 | size_t size; |
126 | 193 | ||
194 | if (pci_use_crs) | ||
195 | pci_bus_remove_resources(bus); | ||
196 | |||
197 | info.bridge = device; | ||
127 | info.bus = bus; | 198 | info.bus = bus; |
128 | info.res_num = 0; | 199 | info.res_num = 0; |
129 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource, | 200 | acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource, |
@@ -163,8 +234,9 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do | |||
163 | #endif | 234 | #endif |
164 | 235 | ||
165 | if (domain && !pci_domains_supported) { | 236 | if (domain && !pci_domains_supported) { |
166 | printk(KERN_WARNING "PCI: Multiple domains not supported " | 237 | printk(KERN_WARNING "pci_bus %04x:%02x: " |
167 | "(dom %d, bus %d)\n", domain, busnum); | 238 | "ignored (multiple domains not supported)\n", |
239 | domain, busnum); | ||
168 | return NULL; | 240 | return NULL; |
169 | } | 241 | } |
170 | 242 | ||
@@ -188,7 +260,8 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do | |||
188 | */ | 260 | */ |
189 | sd = kzalloc(sizeof(*sd), GFP_KERNEL); | 261 | sd = kzalloc(sizeof(*sd), GFP_KERNEL); |
190 | if (!sd) { | 262 | if (!sd) { |
191 | printk(KERN_ERR "PCI: OOM, not probing PCI bus %02x\n", busnum); | 263 | printk(KERN_WARNING "pci_bus %04x:%02x: " |
264 | "ignored (out of memory)\n", domain, busnum); | ||
192 | return NULL; | 265 | return NULL; |
193 | } | 266 | } |
194 | 267 | ||
@@ -209,9 +282,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do | |||
209 | } else { | 282 | } else { |
210 | bus = pci_create_bus(NULL, busnum, &pci_root_ops, sd); | 283 | bus = pci_create_bus(NULL, busnum, &pci_root_ops, sd); |
211 | if (bus) { | 284 | if (bus) { |
212 | if (pci_probe & PCI_USE__CRS) | 285 | get_current_resources(device, busnum, domain, bus); |
213 | get_current_resources(device, busnum, domain, | ||
214 | bus); | ||
215 | bus->subordinate = pci_scan_child_bus(bus); | 286 | bus->subordinate = pci_scan_child_bus(bus); |
216 | } | 287 | } |
217 | } | 288 | } |
@@ -236,17 +307,14 @@ int __init pci_acpi_init(void) | |||
236 | { | 307 | { |
237 | struct pci_dev *dev = NULL; | 308 | struct pci_dev *dev = NULL; |
238 | 309 | ||
239 | if (pcibios_scanned) | ||
240 | return 0; | ||
241 | |||
242 | if (acpi_noirq) | 310 | if (acpi_noirq) |
243 | return 0; | 311 | return -ENODEV; |
244 | 312 | ||
245 | printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n"); | 313 | printk(KERN_INFO "PCI: Using ACPI for IRQ routing\n"); |
246 | acpi_irq_penalty_init(); | 314 | acpi_irq_penalty_init(); |
247 | pcibios_scanned++; | ||
248 | pcibios_enable_irq = acpi_pci_irq_enable; | 315 | pcibios_enable_irq = acpi_pci_irq_enable; |
249 | pcibios_disable_irq = acpi_pci_irq_disable; | 316 | pcibios_disable_irq = acpi_pci_irq_disable; |
317 | x86_init.pci.init_irq = x86_init_noop; | ||
250 | 318 | ||
251 | if (pci_routeirq) { | 319 | if (pci_routeirq) { |
252 | /* | 320 | /* |
diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c index 572ee9782f2a..fc1e8fe07e5c 100644 --- a/arch/x86/pci/amd_bus.c +++ b/arch/x86/pci/amd_bus.c | |||
@@ -2,180 +2,19 @@ | |||
2 | #include <linux/pci.h> | 2 | #include <linux/pci.h> |
3 | #include <linux/topology.h> | 3 | #include <linux/topology.h> |
4 | #include <linux/cpu.h> | 4 | #include <linux/cpu.h> |
5 | #include <linux/range.h> | ||
6 | |||
5 | #include <asm/pci_x86.h> | 7 | #include <asm/pci_x86.h> |
6 | 8 | ||
7 | #ifdef CONFIG_X86_64 | ||
8 | #include <asm/pci-direct.h> | 9 | #include <asm/pci-direct.h> |
9 | #include <asm/mpspec.h> | 10 | |
10 | #include <linux/cpumask.h> | 11 | #include "bus_numa.h" |
11 | #endif | ||
12 | 12 | ||
13 | /* | 13 | /* |
14 | * This discovers the pcibus <-> node mapping on AMD K8. | 14 | * This discovers the pcibus <-> node mapping on AMD K8. |
15 | * also get peer root bus resource for io,mmio | 15 | * also get peer root bus resource for io,mmio |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #ifdef CONFIG_X86_64 | ||
19 | |||
20 | /* | ||
21 | * sub bus (transparent) will use entres from 3 to store extra from root, | ||
22 | * so need to make sure have enought slot there, increase PCI_BUS_NUM_RESOURCES? | ||
23 | */ | ||
24 | #define RES_NUM 16 | ||
25 | struct pci_root_info { | ||
26 | char name[12]; | ||
27 | unsigned int res_num; | ||
28 | struct resource res[RES_NUM]; | ||
29 | int bus_min; | ||
30 | int bus_max; | ||
31 | int node; | ||
32 | int link; | ||
33 | }; | ||
34 | |||
35 | /* 4 at this time, it may become to 32 */ | ||
36 | #define PCI_ROOT_NR 4 | ||
37 | static int pci_root_num; | ||
38 | static struct pci_root_info pci_root_info[PCI_ROOT_NR]; | ||
39 | |||
40 | void x86_pci_root_bus_res_quirks(struct pci_bus *b) | ||
41 | { | ||
42 | int i; | ||
43 | int j; | ||
44 | struct pci_root_info *info; | ||
45 | |||
46 | /* don't go for it if _CRS is used already */ | ||
47 | if (b->resource[0] != &ioport_resource || | ||
48 | b->resource[1] != &iomem_resource) | ||
49 | return; | ||
50 | |||
51 | /* if only one root bus, don't need to anything */ | ||
52 | if (pci_root_num < 2) | ||
53 | return; | ||
54 | |||
55 | for (i = 0; i < pci_root_num; i++) { | ||
56 | if (pci_root_info[i].bus_min == b->number) | ||
57 | break; | ||
58 | } | ||
59 | |||
60 | if (i == pci_root_num) | ||
61 | return; | ||
62 | |||
63 | printk(KERN_DEBUG "PCI: peer root bus %02x res updated from pci conf\n", | ||
64 | b->number); | ||
65 | |||
66 | info = &pci_root_info[i]; | ||
67 | for (j = 0; j < info->res_num; j++) { | ||
68 | struct resource *res; | ||
69 | struct resource *root; | ||
70 | |||
71 | res = &info->res[j]; | ||
72 | b->resource[j] = res; | ||
73 | if (res->flags & IORESOURCE_IO) | ||
74 | root = &ioport_resource; | ||
75 | else | ||
76 | root = &iomem_resource; | ||
77 | insert_resource(root, res); | ||
78 | } | ||
79 | } | ||
80 | |||
81 | #define RANGE_NUM 16 | ||
82 | |||
83 | struct res_range { | ||
84 | size_t start; | ||
85 | size_t end; | ||
86 | }; | ||
87 | |||
88 | static void __init update_range(struct res_range *range, size_t start, | ||
89 | size_t end) | ||
90 | { | ||
91 | int i; | ||
92 | int j; | ||
93 | |||
94 | for (j = 0; j < RANGE_NUM; j++) { | ||
95 | if (!range[j].end) | ||
96 | continue; | ||
97 | |||
98 | if (start <= range[j].start && end >= range[j].end) { | ||
99 | range[j].start = 0; | ||
100 | range[j].end = 0; | ||
101 | continue; | ||
102 | } | ||
103 | |||
104 | if (start <= range[j].start && end < range[j].end && range[j].start < end + 1) { | ||
105 | range[j].start = end + 1; | ||
106 | continue; | ||
107 | } | ||
108 | |||
109 | |||
110 | if (start > range[j].start && end >= range[j].end && range[j].end > start - 1) { | ||
111 | range[j].end = start - 1; | ||
112 | continue; | ||
113 | } | ||
114 | |||
115 | if (start > range[j].start && end < range[j].end) { | ||
116 | /* find the new spare */ | ||
117 | for (i = 0; i < RANGE_NUM; i++) { | ||
118 | if (range[i].end == 0) | ||
119 | break; | ||
120 | } | ||
121 | if (i < RANGE_NUM) { | ||
122 | range[i].end = range[j].end; | ||
123 | range[i].start = end + 1; | ||
124 | } else { | ||
125 | printk(KERN_ERR "run of slot in ranges\n"); | ||
126 | } | ||
127 | range[j].end = start - 1; | ||
128 | continue; | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | |||
133 | static void __init update_res(struct pci_root_info *info, size_t start, | ||
134 | size_t end, unsigned long flags, int merge) | ||
135 | { | ||
136 | int i; | ||
137 | struct resource *res; | ||
138 | |||
139 | if (!merge) | ||
140 | goto addit; | ||
141 | |||
142 | /* try to merge it with old one */ | ||
143 | for (i = 0; i < info->res_num; i++) { | ||
144 | size_t final_start, final_end; | ||
145 | size_t common_start, common_end; | ||
146 | |||
147 | res = &info->res[i]; | ||
148 | if (res->flags != flags) | ||
149 | continue; | ||
150 | |||
151 | common_start = max((size_t)res->start, start); | ||
152 | common_end = min((size_t)res->end, end); | ||
153 | if (common_start > common_end + 1) | ||
154 | continue; | ||
155 | |||
156 | final_start = min((size_t)res->start, start); | ||
157 | final_end = max((size_t)res->end, end); | ||
158 | |||
159 | res->start = final_start; | ||
160 | res->end = final_end; | ||
161 | return; | ||
162 | } | ||
163 | |||
164 | addit: | ||
165 | |||
166 | /* need to add that */ | ||
167 | if (info->res_num >= RES_NUM) | ||
168 | return; | ||
169 | |||
170 | res = &info->res[info->res_num]; | ||
171 | res->name = info->name; | ||
172 | res->flags = flags; | ||
173 | res->start = start; | ||
174 | res->end = end; | ||
175 | res->child = NULL; | ||
176 | info->res_num++; | ||
177 | } | ||
178 | |||
179 | struct pci_hostbridge_probe { | 18 | struct pci_hostbridge_probe { |
180 | u32 bus; | 19 | u32 bus; |
181 | u32 slot; | 20 | u32 slot; |
@@ -218,6 +57,8 @@ static void __init get_pci_mmcfg_amd_fam10h_range(void) | |||
218 | fam10h_mmconf_end = base + (1ULL<<(segn_busn_bits + 20)) - 1; | 57 | fam10h_mmconf_end = base + (1ULL<<(segn_busn_bits + 20)) - 1; |
219 | } | 58 | } |
220 | 59 | ||
60 | #define RANGE_NUM 16 | ||
61 | |||
221 | /** | 62 | /** |
222 | * early_fill_mp_bus_to_node() | 63 | * early_fill_mp_bus_to_node() |
223 | * called before pcibios_scan_root and pci_scan_bus | 64 | * called before pcibios_scan_root and pci_scan_bus |
@@ -230,7 +71,6 @@ static int __init early_fill_mp_bus_info(void) | |||
230 | int j; | 71 | int j; |
231 | unsigned bus; | 72 | unsigned bus; |
232 | unsigned slot; | 73 | unsigned slot; |
233 | int found; | ||
234 | int node; | 74 | int node; |
235 | int link; | 75 | int link; |
236 | int def_node; | 76 | int def_node; |
@@ -238,16 +78,17 @@ static int __init early_fill_mp_bus_info(void) | |||
238 | struct pci_root_info *info; | 78 | struct pci_root_info *info; |
239 | u32 reg; | 79 | u32 reg; |
240 | struct resource *res; | 80 | struct resource *res; |
241 | size_t start; | 81 | u64 start; |
242 | size_t end; | 82 | u64 end; |
243 | struct res_range range[RANGE_NUM]; | 83 | struct range range[RANGE_NUM]; |
244 | u64 val; | 84 | u64 val; |
245 | u32 address; | 85 | u32 address; |
86 | bool found; | ||
246 | 87 | ||
247 | if (!early_pci_allowed()) | 88 | if (!early_pci_allowed()) |
248 | return -1; | 89 | return -1; |
249 | 90 | ||
250 | found = 0; | 91 | found = false; |
251 | for (i = 0; i < ARRAY_SIZE(pci_probes); i++) { | 92 | for (i = 0; i < ARRAY_SIZE(pci_probes); i++) { |
252 | u32 id; | 93 | u32 id; |
253 | u16 device; | 94 | u16 device; |
@@ -261,7 +102,7 @@ static int __init early_fill_mp_bus_info(void) | |||
261 | device = (id>>16) & 0xffff; | 102 | device = (id>>16) & 0xffff; |
262 | if (pci_probes[i].vendor == vendor && | 103 | if (pci_probes[i].vendor == vendor && |
263 | pci_probes[i].device == device) { | 104 | pci_probes[i].device == device) { |
264 | found = 1; | 105 | found = true; |
265 | break; | 106 | break; |
266 | } | 107 | } |
267 | } | 108 | } |
@@ -304,7 +145,7 @@ static int __init early_fill_mp_bus_info(void) | |||
304 | def_link = (reg >> 8) & 0x03; | 145 | def_link = (reg >> 8) & 0x03; |
305 | 146 | ||
306 | memset(range, 0, sizeof(range)); | 147 | memset(range, 0, sizeof(range)); |
307 | range[0].end = 0xffff; | 148 | add_range(range, RANGE_NUM, 0, 0, 0xffff + 1); |
308 | /* io port resource */ | 149 | /* io port resource */ |
309 | for (i = 0; i < 4; i++) { | 150 | for (i = 0; i < 4; i++) { |
310 | reg = read_pci_config(bus, slot, 1, 0xc0 + (i << 3)); | 151 | reg = read_pci_config(bus, slot, 1, 0xc0 + (i << 3)); |
@@ -328,13 +169,13 @@ static int __init early_fill_mp_bus_info(void) | |||
328 | 169 | ||
329 | info = &pci_root_info[j]; | 170 | info = &pci_root_info[j]; |
330 | printk(KERN_DEBUG "node %d link %d: io port [%llx, %llx]\n", | 171 | printk(KERN_DEBUG "node %d link %d: io port [%llx, %llx]\n", |
331 | node, link, (u64)start, (u64)end); | 172 | node, link, start, end); |
332 | 173 | ||
333 | /* kernel only handle 16 bit only */ | 174 | /* kernel only handle 16 bit only */ |
334 | if (end > 0xffff) | 175 | if (end > 0xffff) |
335 | end = 0xffff; | 176 | end = 0xffff; |
336 | update_res(info, start, end, IORESOURCE_IO, 1); | 177 | update_res(info, start, end, IORESOURCE_IO, 1); |
337 | update_range(range, start, end); | 178 | subtract_range(range, RANGE_NUM, start, end + 1); |
338 | } | 179 | } |
339 | /* add left over io port range to def node/link, [0, 0xffff] */ | 180 | /* add left over io port range to def node/link, [0, 0xffff] */ |
340 | /* find the position */ | 181 | /* find the position */ |
@@ -349,29 +190,32 @@ static int __init early_fill_mp_bus_info(void) | |||
349 | if (!range[i].end) | 190 | if (!range[i].end) |
350 | continue; | 191 | continue; |
351 | 192 | ||
352 | update_res(info, range[i].start, range[i].end, | 193 | update_res(info, range[i].start, range[i].end - 1, |
353 | IORESOURCE_IO, 1); | 194 | IORESOURCE_IO, 1); |
354 | } | 195 | } |
355 | } | 196 | } |
356 | 197 | ||
357 | memset(range, 0, sizeof(range)); | 198 | memset(range, 0, sizeof(range)); |
358 | /* 0xfd00000000-0xffffffffff for HT */ | 199 | /* 0xfd00000000-0xffffffffff for HT */ |
359 | range[0].end = (0xfdULL<<32) - 1; | 200 | end = cap_resource((0xfdULL<<32) - 1); |
201 | end++; | ||
202 | add_range(range, RANGE_NUM, 0, 0, end); | ||
360 | 203 | ||
361 | /* need to take out [0, TOM) for RAM*/ | 204 | /* need to take out [0, TOM) for RAM*/ |
362 | address = MSR_K8_TOP_MEM1; | 205 | address = MSR_K8_TOP_MEM1; |
363 | rdmsrl(address, val); | 206 | rdmsrl(address, val); |
364 | end = (val & 0xffffff800000ULL); | 207 | end = (val & 0xffffff800000ULL); |
365 | printk(KERN_INFO "TOM: %016lx aka %ldM\n", end, end>>20); | 208 | printk(KERN_INFO "TOM: %016llx aka %lldM\n", end, end>>20); |
366 | if (end < (1ULL<<32)) | 209 | if (end < (1ULL<<32)) |
367 | update_range(range, 0, end - 1); | 210 | subtract_range(range, RANGE_NUM, 0, end); |
368 | 211 | ||
369 | /* get mmconfig */ | 212 | /* get mmconfig */ |
370 | get_pci_mmcfg_amd_fam10h_range(); | 213 | get_pci_mmcfg_amd_fam10h_range(); |
371 | /* need to take out mmconf range */ | 214 | /* need to take out mmconf range */ |
372 | if (fam10h_mmconf_end) { | 215 | if (fam10h_mmconf_end) { |
373 | printk(KERN_DEBUG "Fam 10h mmconf [%llx, %llx]\n", fam10h_mmconf_start, fam10h_mmconf_end); | 216 | printk(KERN_DEBUG "Fam 10h mmconf [%llx, %llx]\n", fam10h_mmconf_start, fam10h_mmconf_end); |
374 | update_range(range, fam10h_mmconf_start, fam10h_mmconf_end); | 217 | subtract_range(range, RANGE_NUM, fam10h_mmconf_start, |
218 | fam10h_mmconf_end + 1); | ||
375 | } | 219 | } |
376 | 220 | ||
377 | /* mmio resource */ | 221 | /* mmio resource */ |
@@ -401,7 +245,7 @@ static int __init early_fill_mp_bus_info(void) | |||
401 | info = &pci_root_info[j]; | 245 | info = &pci_root_info[j]; |
402 | 246 | ||
403 | printk(KERN_DEBUG "node %d link %d: mmio [%llx, %llx]", | 247 | printk(KERN_DEBUG "node %d link %d: mmio [%llx, %llx]", |
404 | node, link, (u64)start, (u64)end); | 248 | node, link, start, end); |
405 | /* | 249 | /* |
406 | * some sick allocation would have range overlap with fam10h | 250 | * some sick allocation would have range overlap with fam10h |
407 | * mmconf range, so need to update start and end. | 251 | * mmconf range, so need to update start and end. |
@@ -426,14 +270,15 @@ static int __init early_fill_mp_bus_info(void) | |||
426 | /* we got a hole */ | 270 | /* we got a hole */ |
427 | endx = fam10h_mmconf_start - 1; | 271 | endx = fam10h_mmconf_start - 1; |
428 | update_res(info, start, endx, IORESOURCE_MEM, 0); | 272 | update_res(info, start, endx, IORESOURCE_MEM, 0); |
429 | update_range(range, start, endx); | 273 | subtract_range(range, RANGE_NUM, start, |
430 | printk(KERN_CONT " ==> [%llx, %llx]", (u64)start, endx); | 274 | endx + 1); |
275 | printk(KERN_CONT " ==> [%llx, %llx]", start, endx); | ||
431 | start = fam10h_mmconf_end + 1; | 276 | start = fam10h_mmconf_end + 1; |
432 | changed = 1; | 277 | changed = 1; |
433 | } | 278 | } |
434 | if (changed) { | 279 | if (changed) { |
435 | if (start <= end) { | 280 | if (start <= end) { |
436 | printk(KERN_CONT " %s [%llx, %llx]", endx?"and":"==>", (u64)start, (u64)end); | 281 | printk(KERN_CONT " %s [%llx, %llx]", endx ? "and" : "==>", start, end); |
437 | } else { | 282 | } else { |
438 | printk(KERN_CONT "%s\n", endx?"":" ==> none"); | 283 | printk(KERN_CONT "%s\n", endx?"":" ==> none"); |
439 | continue; | 284 | continue; |
@@ -441,8 +286,9 @@ static int __init early_fill_mp_bus_info(void) | |||
441 | } | 286 | } |
442 | } | 287 | } |
443 | 288 | ||
444 | update_res(info, start, end, IORESOURCE_MEM, 1); | 289 | update_res(info, cap_resource(start), cap_resource(end), |
445 | update_range(range, start, end); | 290 | IORESOURCE_MEM, 1); |
291 | subtract_range(range, RANGE_NUM, start, end + 1); | ||
446 | printk(KERN_CONT "\n"); | 292 | printk(KERN_CONT "\n"); |
447 | } | 293 | } |
448 | 294 | ||
@@ -456,8 +302,8 @@ static int __init early_fill_mp_bus_info(void) | |||
456 | address = MSR_K8_TOP_MEM2; | 302 | address = MSR_K8_TOP_MEM2; |
457 | rdmsrl(address, val); | 303 | rdmsrl(address, val); |
458 | end = (val & 0xffffff800000ULL); | 304 | end = (val & 0xffffff800000ULL); |
459 | printk(KERN_INFO "TOM2: %016lx aka %ldM\n", end, end>>20); | 305 | printk(KERN_INFO "TOM2: %016llx aka %lldM\n", end, end>>20); |
460 | update_range(range, 1ULL<<32, end - 1); | 306 | subtract_range(range, RANGE_NUM, 1ULL<<32, end); |
461 | } | 307 | } |
462 | 308 | ||
463 | /* | 309 | /* |
@@ -476,7 +322,8 @@ static int __init early_fill_mp_bus_info(void) | |||
476 | if (!range[i].end) | 322 | if (!range[i].end) |
477 | continue; | 323 | continue; |
478 | 324 | ||
479 | update_res(info, range[i].start, range[i].end, | 325 | update_res(info, cap_resource(range[i].start), |
326 | cap_resource(range[i].end - 1), | ||
480 | IORESOURCE_MEM, 1); | 327 | IORESOURCE_MEM, 1); |
481 | } | 328 | } |
482 | } | 329 | } |
@@ -488,28 +335,18 @@ static int __init early_fill_mp_bus_info(void) | |||
488 | info = &pci_root_info[i]; | 335 | info = &pci_root_info[i]; |
489 | res_num = info->res_num; | 336 | res_num = info->res_num; |
490 | busnum = info->bus_min; | 337 | busnum = info->bus_min; |
491 | printk(KERN_DEBUG "bus: [%02x,%02x] on node %x link %x\n", | 338 | printk(KERN_DEBUG "bus: [%02x, %02x] on node %x link %x\n", |
492 | info->bus_min, info->bus_max, info->node, info->link); | 339 | info->bus_min, info->bus_max, info->node, info->link); |
493 | for (j = 0; j < res_num; j++) { | 340 | for (j = 0; j < res_num; j++) { |
494 | res = &info->res[j]; | 341 | res = &info->res[j]; |
495 | printk(KERN_DEBUG "bus: %02x index %x %s: [%llx, %llx]\n", | 342 | printk(KERN_DEBUG "bus: %02x index %x %pR\n", |
496 | busnum, j, | 343 | busnum, j, res); |
497 | (res->flags & IORESOURCE_IO)?"io port":"mmio", | ||
498 | res->start, res->end); | ||
499 | } | 344 | } |
500 | } | 345 | } |
501 | 346 | ||
502 | return 0; | 347 | return 0; |
503 | } | 348 | } |
504 | 349 | ||
505 | #else /* !CONFIG_X86_64 */ | ||
506 | |||
507 | static int __init early_fill_mp_bus_info(void) { return 0; } | ||
508 | |||
509 | #endif /* !CONFIG_X86_64 */ | ||
510 | |||
511 | /* common 32/64 bit code */ | ||
512 | |||
513 | #define ENABLE_CF8_EXT_CFG (1ULL << 46) | 350 | #define ENABLE_CF8_EXT_CFG (1ULL << 46) |
514 | 351 | ||
515 | static void enable_pci_io_ecs(void *unused) | 352 | static void enable_pci_io_ecs(void *unused) |
diff --git a/arch/x86/pci/bus_numa.c b/arch/x86/pci/bus_numa.c new file mode 100644 index 000000000000..64a122883896 --- /dev/null +++ b/arch/x86/pci/bus_numa.c | |||
@@ -0,0 +1,101 @@ | |||
1 | #include <linux/init.h> | ||
2 | #include <linux/pci.h> | ||
3 | #include <linux/range.h> | ||
4 | |||
5 | #include "bus_numa.h" | ||
6 | |||
7 | int pci_root_num; | ||
8 | struct pci_root_info pci_root_info[PCI_ROOT_NR]; | ||
9 | |||
10 | void x86_pci_root_bus_res_quirks(struct pci_bus *b) | ||
11 | { | ||
12 | int i; | ||
13 | int j; | ||
14 | struct pci_root_info *info; | ||
15 | |||
16 | /* don't go for it if _CRS is used already */ | ||
17 | if (b->resource[0] != &ioport_resource || | ||
18 | b->resource[1] != &iomem_resource) | ||
19 | return; | ||
20 | |||
21 | if (!pci_root_num) | ||
22 | return; | ||
23 | |||
24 | for (i = 0; i < pci_root_num; i++) { | ||
25 | if (pci_root_info[i].bus_min == b->number) | ||
26 | break; | ||
27 | } | ||
28 | |||
29 | if (i == pci_root_num) | ||
30 | return; | ||
31 | |||
32 | printk(KERN_DEBUG "PCI: peer root bus %02x res updated from pci conf\n", | ||
33 | b->number); | ||
34 | |||
35 | pci_bus_remove_resources(b); | ||
36 | info = &pci_root_info[i]; | ||
37 | for (j = 0; j < info->res_num; j++) { | ||
38 | struct resource *res; | ||
39 | struct resource *root; | ||
40 | |||
41 | res = &info->res[j]; | ||
42 | pci_bus_add_resource(b, res, 0); | ||
43 | if (res->flags & IORESOURCE_IO) | ||
44 | root = &ioport_resource; | ||
45 | else | ||
46 | root = &iomem_resource; | ||
47 | insert_resource(root, res); | ||
48 | } | ||
49 | } | ||
50 | |||
51 | void __devinit update_res(struct pci_root_info *info, resource_size_t start, | ||
52 | resource_size_t end, unsigned long flags, int merge) | ||
53 | { | ||
54 | int i; | ||
55 | struct resource *res; | ||
56 | |||
57 | if (start > end) | ||
58 | return; | ||
59 | |||
60 | if (start == MAX_RESOURCE) | ||
61 | return; | ||
62 | |||
63 | if (!merge) | ||
64 | goto addit; | ||
65 | |||
66 | /* try to merge it with old one */ | ||
67 | for (i = 0; i < info->res_num; i++) { | ||
68 | resource_size_t final_start, final_end; | ||
69 | resource_size_t common_start, common_end; | ||
70 | |||
71 | res = &info->res[i]; | ||
72 | if (res->flags != flags) | ||
73 | continue; | ||
74 | |||
75 | common_start = max(res->start, start); | ||
76 | common_end = min(res->end, end); | ||
77 | if (common_start > common_end + 1) | ||
78 | continue; | ||
79 | |||
80 | final_start = min(res->start, start); | ||
81 | final_end = max(res->end, end); | ||
82 | |||
83 | res->start = final_start; | ||
84 | res->end = final_end; | ||
85 | return; | ||
86 | } | ||
87 | |||
88 | addit: | ||
89 | |||
90 | /* need to add that */ | ||
91 | if (info->res_num >= RES_NUM) | ||
92 | return; | ||
93 | |||
94 | res = &info->res[info->res_num]; | ||
95 | res->name = info->name; | ||
96 | res->flags = flags; | ||
97 | res->start = start; | ||
98 | res->end = end; | ||
99 | res->child = NULL; | ||
100 | info->res_num++; | ||
101 | } | ||
diff --git a/arch/x86/pci/bus_numa.h b/arch/x86/pci/bus_numa.h new file mode 100644 index 000000000000..804a4b40c31a --- /dev/null +++ b/arch/x86/pci/bus_numa.h | |||
@@ -0,0 +1,25 @@ | |||
1 | #ifndef __BUS_NUMA_H | ||
2 | #define __BUS_NUMA_H | ||
3 | /* | ||
4 | * sub bus (transparent) will use entres from 3 to store extra from | ||
5 | * root, so need to make sure we have enough slot there. | ||
6 | */ | ||
7 | #define RES_NUM 16 | ||
8 | struct pci_root_info { | ||
9 | char name[12]; | ||
10 | unsigned int res_num; | ||
11 | struct resource res[RES_NUM]; | ||
12 | int bus_min; | ||
13 | int bus_max; | ||
14 | int node; | ||
15 | int link; | ||
16 | }; | ||
17 | |||
18 | /* 4 at this time, it may become to 32 */ | ||
19 | #define PCI_ROOT_NR 4 | ||
20 | extern int pci_root_num; | ||
21 | extern struct pci_root_info pci_root_info[PCI_ROOT_NR]; | ||
22 | |||
23 | extern void update_res(struct pci_root_info *info, resource_size_t start, | ||
24 | resource_size_t end, unsigned long flags, int merge); | ||
25 | #endif | ||
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c index 1331fcf26143..cf2e93869c48 100644 --- a/arch/x86/pci/common.c +++ b/arch/x86/pci/common.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <linux/ioport.h> | 9 | #include <linux/ioport.h> |
10 | #include <linux/init.h> | 10 | #include <linux/init.h> |
11 | #include <linux/dmi.h> | 11 | #include <linux/dmi.h> |
12 | #include <linux/slab.h> | ||
12 | 13 | ||
13 | #include <asm/acpi.h> | 14 | #include <asm/acpi.h> |
14 | #include <asm/segment.h> | 15 | #include <asm/segment.h> |
@@ -72,12 +73,6 @@ struct pci_ops pci_root_ops = { | |||
72 | }; | 73 | }; |
73 | 74 | ||
74 | /* | 75 | /* |
75 | * legacy, numa, and acpi all want to call pcibios_scan_root | ||
76 | * from their initcalls. This flag prevents that. | ||
77 | */ | ||
78 | int pcibios_scanned; | ||
79 | |||
80 | /* | ||
81 | * This interrupt-safe spinlock protects all accesses to PCI | 76 | * This interrupt-safe spinlock protects all accesses to PCI |
82 | * configuration space. | 77 | * configuration space. |
83 | */ | 78 | */ |
@@ -410,8 +405,6 @@ struct pci_bus * __devinit pcibios_scan_root(int busnum) | |||
410 | return bus; | 405 | return bus; |
411 | } | 406 | } |
412 | 407 | ||
413 | extern u8 pci_cache_line_size; | ||
414 | |||
415 | int __init pcibios_init(void) | 408 | int __init pcibios_init(void) |
416 | { | 409 | { |
417 | struct cpuinfo_x86 *c = &boot_cpu_data; | 410 | struct cpuinfo_x86 *c = &boot_cpu_data; |
@@ -422,15 +415,19 @@ int __init pcibios_init(void) | |||
422 | } | 415 | } |
423 | 416 | ||
424 | /* | 417 | /* |
425 | * Assume PCI cacheline size of 32 bytes for all x86s except K7/K8 | 418 | * Set PCI cacheline size to that of the CPU if the CPU has reported it. |
426 | * and P4. It's also good for 386/486s (which actually have 16) | 419 | * (For older CPUs that don't support cpuid, we se it to 32 bytes |
420 | * It's also good for 386/486s (which actually have 16) | ||
427 | * as quite a few PCI devices do not support smaller values. | 421 | * as quite a few PCI devices do not support smaller values. |
428 | */ | 422 | */ |
429 | pci_cache_line_size = 32 >> 2; | 423 | if (c->x86_clflush_size > 0) { |
430 | if (c->x86 >= 6 && c->x86_vendor == X86_VENDOR_AMD) | 424 | pci_dfl_cache_line_size = c->x86_clflush_size >> 2; |
431 | pci_cache_line_size = 64 >> 2; /* K7 & K8 */ | 425 | printk(KERN_DEBUG "PCI: pci_cache_line_size set to %d bytes\n", |
432 | else if (c->x86 > 6 && c->x86_vendor == X86_VENDOR_INTEL) | 426 | pci_dfl_cache_line_size << 2); |
433 | pci_cache_line_size = 128 >> 2; /* P4 */ | 427 | } else { |
428 | pci_dfl_cache_line_size = 32 >> 2; | ||
429 | printk(KERN_DEBUG "PCI: Unknown cacheline size. Setting to 32 bytes\n"); | ||
430 | } | ||
434 | 431 | ||
435 | pcibios_resource_survey(); | 432 | pcibios_resource_survey(); |
436 | 433 | ||
@@ -518,6 +515,9 @@ char * __devinit pcibios_setup(char *str) | |||
518 | } else if (!strcmp(str, "use_crs")) { | 515 | } else if (!strcmp(str, "use_crs")) { |
519 | pci_probe |= PCI_USE__CRS; | 516 | pci_probe |= PCI_USE__CRS; |
520 | return NULL; | 517 | return NULL; |
518 | } else if (!strcmp(str, "nocrs")) { | ||
519 | pci_probe |= PCI_ROOT_NO_CRS; | ||
520 | return NULL; | ||
521 | } else if (!strcmp(str, "earlydump")) { | 521 | } else if (!strcmp(str, "earlydump")) { |
522 | pci_early_dump_regs = 1; | 522 | pci_early_dump_regs = 1; |
523 | return NULL; | 523 | return NULL; |
diff --git a/arch/x86/pci/early.c b/arch/x86/pci/early.c index aaf26ae58cd5..d1067d539bee 100644 --- a/arch/x86/pci/early.c +++ b/arch/x86/pci/early.c | |||
@@ -12,8 +12,6 @@ u32 read_pci_config(u8 bus, u8 slot, u8 func, u8 offset) | |||
12 | u32 v; | 12 | u32 v; |
13 | outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); | 13 | outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); |
14 | v = inl(0xcfc); | 14 | v = inl(0xcfc); |
15 | if (v != 0xffffffff) | ||
16 | pr_debug("%x reading 4 from %x: %x\n", slot, offset, v); | ||
17 | return v; | 15 | return v; |
18 | } | 16 | } |
19 | 17 | ||
@@ -22,7 +20,6 @@ u8 read_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset) | |||
22 | u8 v; | 20 | u8 v; |
23 | outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); | 21 | outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); |
24 | v = inb(0xcfc + (offset&3)); | 22 | v = inb(0xcfc + (offset&3)); |
25 | pr_debug("%x reading 1 from %x: %x\n", slot, offset, v); | ||
26 | return v; | 23 | return v; |
27 | } | 24 | } |
28 | 25 | ||
@@ -31,28 +28,24 @@ u16 read_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset) | |||
31 | u16 v; | 28 | u16 v; |
32 | outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); | 29 | outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); |
33 | v = inw(0xcfc + (offset&2)); | 30 | v = inw(0xcfc + (offset&2)); |
34 | pr_debug("%x reading 2 from %x: %x\n", slot, offset, v); | ||
35 | return v; | 31 | return v; |
36 | } | 32 | } |
37 | 33 | ||
38 | void write_pci_config(u8 bus, u8 slot, u8 func, u8 offset, | 34 | void write_pci_config(u8 bus, u8 slot, u8 func, u8 offset, |
39 | u32 val) | 35 | u32 val) |
40 | { | 36 | { |
41 | pr_debug("%x writing to %x: %x\n", slot, offset, val); | ||
42 | outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); | 37 | outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); |
43 | outl(val, 0xcfc); | 38 | outl(val, 0xcfc); |
44 | } | 39 | } |
45 | 40 | ||
46 | void write_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset, u8 val) | 41 | void write_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset, u8 val) |
47 | { | 42 | { |
48 | pr_debug("%x writing to %x: %x\n", slot, offset, val); | ||
49 | outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); | 43 | outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); |
50 | outb(val, 0xcfc + (offset&3)); | 44 | outb(val, 0xcfc + (offset&3)); |
51 | } | 45 | } |
52 | 46 | ||
53 | void write_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset, u16 val) | 47 | void write_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset, u16 val) |
54 | { | 48 | { |
55 | pr_debug("%x writing to %x: %x\n", slot, offset, val); | ||
56 | outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); | 49 | outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); |
57 | outw(val, 0xcfc + (offset&2)); | 50 | outw(val, 0xcfc + (offset&2)); |
58 | } | 51 | } |
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c index b22d13b0c71d..97da2ba9344b 100644 --- a/arch/x86/pci/i386.c +++ b/arch/x86/pci/i386.c | |||
@@ -60,22 +60,23 @@ skip_isa_ioresource_align(struct pci_dev *dev) { | |||
60 | * but we want to try to avoid allocating at 0x2900-0x2bff | 60 | * but we want to try to avoid allocating at 0x2900-0x2bff |
61 | * which might have be mirrored at 0x0100-0x03ff.. | 61 | * which might have be mirrored at 0x0100-0x03ff.. |
62 | */ | 62 | */ |
63 | void | 63 | resource_size_t |
64 | pcibios_align_resource(void *data, struct resource *res, | 64 | pcibios_align_resource(void *data, const struct resource *res, |
65 | resource_size_t size, resource_size_t align) | 65 | resource_size_t size, resource_size_t align) |
66 | { | 66 | { |
67 | struct pci_dev *dev = data; | 67 | struct pci_dev *dev = data; |
68 | resource_size_t start = res->start; | ||
68 | 69 | ||
69 | if (res->flags & IORESOURCE_IO) { | 70 | if (res->flags & IORESOURCE_IO) { |
70 | resource_size_t start = res->start; | ||
71 | |||
72 | if (skip_isa_ioresource_align(dev)) | 71 | if (skip_isa_ioresource_align(dev)) |
73 | return; | 72 | return start; |
74 | if (start & 0x300) { | 73 | if (start & 0x300) |
75 | start = (start + 0x3ff) & ~0x3ff; | 74 | start = (start + 0x3ff) & ~0x3ff; |
76 | res->start = start; | 75 | } else if (res->flags & IORESOURCE_MEM) { |
77 | } | 76 | if (start < BIOS_END) |
77 | start = BIOS_END; | ||
78 | } | 78 | } |
79 | return start; | ||
79 | } | 80 | } |
80 | EXPORT_SYMBOL(pcibios_align_resource); | 81 | EXPORT_SYMBOL(pcibios_align_resource); |
81 | 82 | ||
@@ -129,7 +130,6 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) | |||
129 | continue; | 130 | continue; |
130 | if (!r->start || | 131 | if (!r->start || |
131 | pci_claim_resource(dev, idx) < 0) { | 132 | pci_claim_resource(dev, idx) < 0) { |
132 | dev_info(&dev->dev, "BAR %d: can't allocate resource\n", idx); | ||
133 | /* | 133 | /* |
134 | * Something is wrong with the region. | 134 | * Something is wrong with the region. |
135 | * Invalidate the resource to prevent | 135 | * Invalidate the resource to prevent |
@@ -144,16 +144,29 @@ static void __init pcibios_allocate_bus_resources(struct list_head *bus_list) | |||
144 | } | 144 | } |
145 | } | 145 | } |
146 | 146 | ||
147 | struct pci_check_idx_range { | ||
148 | int start; | ||
149 | int end; | ||
150 | }; | ||
151 | |||
147 | static void __init pcibios_allocate_resources(int pass) | 152 | static void __init pcibios_allocate_resources(int pass) |
148 | { | 153 | { |
149 | struct pci_dev *dev = NULL; | 154 | struct pci_dev *dev = NULL; |
150 | int idx, disabled; | 155 | int idx, disabled, i; |
151 | u16 command; | 156 | u16 command; |
152 | struct resource *r; | 157 | struct resource *r; |
153 | 158 | ||
159 | struct pci_check_idx_range idx_range[] = { | ||
160 | { PCI_STD_RESOURCES, PCI_STD_RESOURCE_END }, | ||
161 | #ifdef CONFIG_PCI_IOV | ||
162 | { PCI_IOV_RESOURCES, PCI_IOV_RESOURCE_END }, | ||
163 | #endif | ||
164 | }; | ||
165 | |||
154 | for_each_pci_dev(dev) { | 166 | for_each_pci_dev(dev) { |
155 | pci_read_config_word(dev, PCI_COMMAND, &command); | 167 | pci_read_config_word(dev, PCI_COMMAND, &command); |
156 | for (idx = 0; idx < PCI_ROM_RESOURCE; idx++) { | 168 | for (i = 0; i < ARRAY_SIZE(idx_range); i++) |
169 | for (idx = idx_range[i].start; idx <= idx_range[i].end; idx++) { | ||
157 | r = &dev->resource[idx]; | 170 | r = &dev->resource[idx]; |
158 | if (r->parent) /* Already allocated */ | 171 | if (r->parent) /* Already allocated */ |
159 | continue; | 172 | continue; |
@@ -164,12 +177,10 @@ static void __init pcibios_allocate_resources(int pass) | |||
164 | else | 177 | else |
165 | disabled = !(command & PCI_COMMAND_MEMORY); | 178 | disabled = !(command & PCI_COMMAND_MEMORY); |
166 | if (pass == disabled) { | 179 | if (pass == disabled) { |
167 | dev_dbg(&dev->dev, "resource %#08llx-%#08llx (f=%lx, d=%d, p=%d)\n", | 180 | dev_dbg(&dev->dev, |
168 | (unsigned long long) r->start, | 181 | "BAR %d: reserving %pr (d=%d, p=%d)\n", |
169 | (unsigned long long) r->end, | 182 | idx, r, disabled, pass); |
170 | r->flags, disabled, pass); | ||
171 | if (pci_claim_resource(dev, idx) < 0) { | 183 | if (pci_claim_resource(dev, idx) < 0) { |
172 | dev_info(&dev->dev, "BAR %d: can't allocate resource\n", idx); | ||
173 | /* We'll assign a new address later */ | 184 | /* We'll assign a new address later */ |
174 | r->end -= r->start; | 185 | r->end -= r->start; |
175 | r->start = 0; | 186 | r->start = 0; |
@@ -182,7 +193,7 @@ static void __init pcibios_allocate_resources(int pass) | |||
182 | /* Turn the ROM off, leave the resource region, | 193 | /* Turn the ROM off, leave the resource region, |
183 | * but keep it unregistered. */ | 194 | * but keep it unregistered. */ |
184 | u32 reg; | 195 | u32 reg; |
185 | dev_dbg(&dev->dev, "disabling ROM\n"); | 196 | dev_dbg(&dev->dev, "disabling ROM %pR\n", r); |
186 | r->flags &= ~IORESOURCE_ROM_ENABLE; | 197 | r->flags &= ~IORESOURCE_ROM_ENABLE; |
187 | pci_read_config_dword(dev, | 198 | pci_read_config_dword(dev, |
188 | dev->rom_base_reg, ®); | 199 | dev->rom_base_reg, ®); |
@@ -242,10 +253,6 @@ void __init pcibios_resource_survey(void) | |||
242 | */ | 253 | */ |
243 | fs_initcall(pcibios_assign_resources); | 254 | fs_initcall(pcibios_assign_resources); |
244 | 255 | ||
245 | void __weak x86_pci_root_bus_res_quirks(struct pci_bus *b) | ||
246 | { | ||
247 | } | ||
248 | |||
249 | /* | 256 | /* |
250 | * If we set up a device for bus mastering, we need to check the latency | 257 | * If we set up a device for bus mastering, we need to check the latency |
251 | * timer as certain crappy BIOSes forget to set it properly. | 258 | * timer as certain crappy BIOSes forget to set it properly. |
@@ -282,6 +289,15 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma, | |||
282 | return -EINVAL; | 289 | return -EINVAL; |
283 | 290 | ||
284 | prot = pgprot_val(vma->vm_page_prot); | 291 | prot = pgprot_val(vma->vm_page_prot); |
292 | |||
293 | /* | ||
294 | * Return error if pat is not enabled and write_combine is requested. | ||
295 | * Caller can followup with UC MINUS request and add a WC mtrr if there | ||
296 | * is a free mtrr slot. | ||
297 | */ | ||
298 | if (!pat_enabled && write_combine) | ||
299 | return -EINVAL; | ||
300 | |||
285 | if (pat_enabled && write_combine) | 301 | if (pat_enabled && write_combine) |
286 | prot |= _PAGE_CACHE_WC; | 302 | prot |= _PAGE_CACHE_WC; |
287 | else if (pat_enabled || boot_cpu_data.x86 > 3) | 303 | else if (pat_enabled || boot_cpu_data.x86 > 3) |
diff --git a/arch/x86/pci/init.c b/arch/x86/pci/init.c index 25a1f8efed4a..adb62aaa7ecd 100644 --- a/arch/x86/pci/init.c +++ b/arch/x86/pci/init.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #include <linux/pci.h> | 1 | #include <linux/pci.h> |
2 | #include <linux/init.h> | 2 | #include <linux/init.h> |
3 | #include <asm/pci_x86.h> | 3 | #include <asm/pci_x86.h> |
4 | #include <asm/x86_init.h> | ||
4 | 5 | ||
5 | /* arch_initcall has too random ordering, so call the initializers | 6 | /* arch_initcall has too random ordering, so call the initializers |
6 | in the right sequence from here. */ | 7 | in the right sequence from here. */ |
@@ -15,10 +16,9 @@ static __init int pci_arch_init(void) | |||
15 | if (!(pci_probe & PCI_PROBE_NOEARLY)) | 16 | if (!(pci_probe & PCI_PROBE_NOEARLY)) |
16 | pci_mmcfg_early_init(); | 17 | pci_mmcfg_early_init(); |
17 | 18 | ||
18 | #ifdef CONFIG_PCI_OLPC | 19 | if (x86_init.pci.arch_init && !x86_init.pci.arch_init()) |
19 | if (!pci_olpc_init()) | 20 | return 0; |
20 | return 0; /* skip additional checks if it's an XO */ | 21 | |
21 | #endif | ||
22 | #ifdef CONFIG_PCI_BIOS | 22 | #ifdef CONFIG_PCI_BIOS |
23 | pci_pcbios_init(); | 23 | pci_pcbios_init(); |
24 | #endif | 24 | #endif |
diff --git a/arch/x86/pci/irq.c b/arch/x86/pci/irq.c index 0696d506c4ad..5d362b5ba06f 100644 --- a/arch/x86/pci/irq.c +++ b/arch/x86/pci/irq.c | |||
@@ -8,7 +8,6 @@ | |||
8 | #include <linux/kernel.h> | 8 | #include <linux/kernel.h> |
9 | #include <linux/pci.h> | 9 | #include <linux/pci.h> |
10 | #include <linux/init.h> | 10 | #include <linux/init.h> |
11 | #include <linux/slab.h> | ||
12 | #include <linux/interrupt.h> | 11 | #include <linux/interrupt.h> |
13 | #include <linux/dmi.h> | 12 | #include <linux/dmi.h> |
14 | #include <linux/io.h> | 13 | #include <linux/io.h> |
@@ -53,7 +52,7 @@ struct irq_router_handler { | |||
53 | int (*probe)(struct irq_router *r, struct pci_dev *router, u16 device); | 52 | int (*probe)(struct irq_router *r, struct pci_dev *router, u16 device); |
54 | }; | 53 | }; |
55 | 54 | ||
56 | int (*pcibios_enable_irq)(struct pci_dev *dev) = NULL; | 55 | int (*pcibios_enable_irq)(struct pci_dev *dev) = pirq_enable_irq; |
57 | void (*pcibios_disable_irq)(struct pci_dev *dev) = NULL; | 56 | void (*pcibios_disable_irq)(struct pci_dev *dev) = NULL; |
58 | 57 | ||
59 | /* | 58 | /* |
@@ -590,6 +589,8 @@ static __init int intel_router_probe(struct irq_router *r, struct pci_dev *route | |||
590 | case PCI_DEVICE_ID_INTEL_ICH10_1: | 589 | case PCI_DEVICE_ID_INTEL_ICH10_1: |
591 | case PCI_DEVICE_ID_INTEL_ICH10_2: | 590 | case PCI_DEVICE_ID_INTEL_ICH10_2: |
592 | case PCI_DEVICE_ID_INTEL_ICH10_3: | 591 | case PCI_DEVICE_ID_INTEL_ICH10_3: |
592 | case PCI_DEVICE_ID_INTEL_CPT_LPC1: | ||
593 | case PCI_DEVICE_ID_INTEL_CPT_LPC2: | ||
593 | r->name = "PIIX/ICH"; | 594 | r->name = "PIIX/ICH"; |
594 | r->get = pirq_piix_get; | 595 | r->get = pirq_piix_get; |
595 | r->set = pirq_piix_set; | 596 | r->set = pirq_piix_set; |
@@ -1016,7 +1017,7 @@ static int pcibios_lookup_irq(struct pci_dev *dev, int assign) | |||
1016 | return 1; | 1017 | return 1; |
1017 | } | 1018 | } |
1018 | 1019 | ||
1019 | static void __init pcibios_fixup_irqs(void) | 1020 | void __init pcibios_fixup_irqs(void) |
1020 | { | 1021 | { |
1021 | struct pci_dev *dev = NULL; | 1022 | struct pci_dev *dev = NULL; |
1022 | u8 pin; | 1023 | u8 pin; |
@@ -1110,12 +1111,12 @@ static struct dmi_system_id __initdata pciirq_dmi_table[] = { | |||
1110 | { } | 1111 | { } |
1111 | }; | 1112 | }; |
1112 | 1113 | ||
1113 | int __init pcibios_irq_init(void) | 1114 | void __init pcibios_irq_init(void) |
1114 | { | 1115 | { |
1115 | DBG(KERN_DEBUG "PCI: IRQ init\n"); | 1116 | DBG(KERN_DEBUG "PCI: IRQ init\n"); |
1116 | 1117 | ||
1117 | if (pcibios_enable_irq || raw_pci_ops == NULL) | 1118 | if (raw_pci_ops == NULL) |
1118 | return 0; | 1119 | return; |
1119 | 1120 | ||
1120 | dmi_check_system(pciirq_dmi_table); | 1121 | dmi_check_system(pciirq_dmi_table); |
1121 | 1122 | ||
@@ -1142,9 +1143,7 @@ int __init pcibios_irq_init(void) | |||
1142 | pirq_table = NULL; | 1143 | pirq_table = NULL; |
1143 | } | 1144 | } |
1144 | 1145 | ||
1145 | pcibios_enable_irq = pirq_enable_irq; | 1146 | x86_init.pci.fixup_irqs(); |
1146 | |||
1147 | pcibios_fixup_irqs(); | ||
1148 | 1147 | ||
1149 | if (io_apic_assign_pci_irqs && pci_routeirq) { | 1148 | if (io_apic_assign_pci_irqs && pci_routeirq) { |
1150 | struct pci_dev *dev = NULL; | 1149 | struct pci_dev *dev = NULL; |
@@ -1157,8 +1156,6 @@ int __init pcibios_irq_init(void) | |||
1157 | for_each_pci_dev(dev) | 1156 | for_each_pci_dev(dev) |
1158 | pirq_enable_irq(dev); | 1157 | pirq_enable_irq(dev); |
1159 | } | 1158 | } |
1160 | |||
1161 | return 0; | ||
1162 | } | 1159 | } |
1163 | 1160 | ||
1164 | static void pirq_penalize_isa_irq(int irq, int active) | 1161 | static void pirq_penalize_isa_irq(int irq, int active) |
diff --git a/arch/x86/pci/legacy.c b/arch/x86/pci/legacy.c index 4061bb0f267d..0db5eaf54560 100644 --- a/arch/x86/pci/legacy.c +++ b/arch/x86/pci/legacy.c | |||
@@ -35,16 +35,13 @@ static void __devinit pcibios_fixup_peer_bridges(void) | |||
35 | } | 35 | } |
36 | } | 36 | } |
37 | 37 | ||
38 | static int __init pci_legacy_init(void) | 38 | int __init pci_legacy_init(void) |
39 | { | 39 | { |
40 | if (!raw_pci_ops) { | 40 | if (!raw_pci_ops) { |
41 | printk("PCI: System does not support PCI\n"); | 41 | printk("PCI: System does not support PCI\n"); |
42 | return 0; | 42 | return 0; |
43 | } | 43 | } |
44 | 44 | ||
45 | if (pcibios_scanned++) | ||
46 | return 0; | ||
47 | |||
48 | printk("PCI: Probing PCI hardware\n"); | 45 | printk("PCI: Probing PCI hardware\n"); |
49 | pci_root_bus = pcibios_scan_root(0); | 46 | pci_root_bus = pcibios_scan_root(0); |
50 | if (pci_root_bus) | 47 | if (pci_root_bus) |
@@ -55,18 +52,15 @@ static int __init pci_legacy_init(void) | |||
55 | 52 | ||
56 | int __init pci_subsys_init(void) | 53 | int __init pci_subsys_init(void) |
57 | { | 54 | { |
58 | #ifdef CONFIG_X86_NUMAQ | 55 | /* |
59 | pci_numaq_init(); | 56 | * The init function returns an non zero value when |
60 | #endif | 57 | * pci_legacy_init should be invoked. |
61 | #ifdef CONFIG_ACPI | 58 | */ |
62 | pci_acpi_init(); | 59 | if (x86_init.pci.init()) |
63 | #endif | 60 | pci_legacy_init(); |
64 | #ifdef CONFIG_X86_VISWS | 61 | |
65 | pci_visws_init(); | ||
66 | #endif | ||
67 | pci_legacy_init(); | ||
68 | pcibios_fixup_peer_bridges(); | 62 | pcibios_fixup_peer_bridges(); |
69 | pcibios_irq_init(); | 63 | x86_init.pci.init_irq(); |
70 | pcibios_init(); | 64 | pcibios_init(); |
71 | 65 | ||
72 | return 0; | 66 | return 0; |
diff --git a/arch/x86/pci/mmconfig-shared.c b/arch/x86/pci/mmconfig-shared.c index 602c172d3bd5..39b9ebe8f886 100644 --- a/arch/x86/pci/mmconfig-shared.c +++ b/arch/x86/pci/mmconfig-shared.c | |||
@@ -15,48 +15,99 @@ | |||
15 | #include <linux/acpi.h> | 15 | #include <linux/acpi.h> |
16 | #include <linux/sfi_acpi.h> | 16 | #include <linux/sfi_acpi.h> |
17 | #include <linux/bitmap.h> | 17 | #include <linux/bitmap.h> |
18 | #include <linux/sort.h> | 18 | #include <linux/dmi.h> |
19 | #include <linux/slab.h> | ||
19 | #include <asm/e820.h> | 20 | #include <asm/e820.h> |
20 | #include <asm/pci_x86.h> | 21 | #include <asm/pci_x86.h> |
21 | #include <asm/acpi.h> | 22 | #include <asm/acpi.h> |
22 | 23 | ||
23 | #define PREFIX "PCI: " | 24 | #define PREFIX "PCI: " |
24 | 25 | ||
25 | /* aperture is up to 256MB but BIOS may reserve less */ | ||
26 | #define MMCONFIG_APER_MIN (2 * 1024*1024) | ||
27 | #define MMCONFIG_APER_MAX (256 * 1024*1024) | ||
28 | |||
29 | /* Indicate if the mmcfg resources have been placed into the resource table. */ | 26 | /* Indicate if the mmcfg resources have been placed into the resource table. */ |
30 | static int __initdata pci_mmcfg_resources_inserted; | 27 | static int __initdata pci_mmcfg_resources_inserted; |
31 | 28 | ||
32 | static __init int extend_mmcfg(int num) | 29 | LIST_HEAD(pci_mmcfg_list); |
30 | |||
31 | static __init void pci_mmconfig_remove(struct pci_mmcfg_region *cfg) | ||
33 | { | 32 | { |
34 | struct acpi_mcfg_allocation *new; | 33 | if (cfg->res.parent) |
35 | int new_num = pci_mmcfg_config_num + num; | 34 | release_resource(&cfg->res); |
35 | list_del(&cfg->list); | ||
36 | kfree(cfg); | ||
37 | } | ||
36 | 38 | ||
37 | new = kzalloc(sizeof(pci_mmcfg_config[0]) * new_num, GFP_KERNEL); | 39 | static __init void free_all_mmcfg(void) |
38 | if (!new) | 40 | { |
39 | return -1; | 41 | struct pci_mmcfg_region *cfg, *tmp; |
42 | |||
43 | pci_mmcfg_arch_free(); | ||
44 | list_for_each_entry_safe(cfg, tmp, &pci_mmcfg_list, list) | ||
45 | pci_mmconfig_remove(cfg); | ||
46 | } | ||
40 | 47 | ||
41 | if (pci_mmcfg_config) { | 48 | static __init void list_add_sorted(struct pci_mmcfg_region *new) |
42 | memcpy(new, pci_mmcfg_config, | 49 | { |
43 | sizeof(pci_mmcfg_config[0]) * new_num); | 50 | struct pci_mmcfg_region *cfg; |
44 | kfree(pci_mmcfg_config); | 51 | |
52 | /* keep list sorted by segment and starting bus number */ | ||
53 | list_for_each_entry(cfg, &pci_mmcfg_list, list) { | ||
54 | if (cfg->segment > new->segment || | ||
55 | (cfg->segment == new->segment && | ||
56 | cfg->start_bus >= new->start_bus)) { | ||
57 | list_add_tail(&new->list, &cfg->list); | ||
58 | return; | ||
59 | } | ||
45 | } | 60 | } |
46 | pci_mmcfg_config = new; | 61 | list_add_tail(&new->list, &pci_mmcfg_list); |
62 | } | ||
47 | 63 | ||
48 | return 0; | 64 | static __init struct pci_mmcfg_region *pci_mmconfig_add(int segment, int start, |
65 | int end, u64 addr) | ||
66 | { | ||
67 | struct pci_mmcfg_region *new; | ||
68 | int num_buses; | ||
69 | struct resource *res; | ||
70 | |||
71 | if (addr == 0) | ||
72 | return NULL; | ||
73 | |||
74 | new = kzalloc(sizeof(*new), GFP_KERNEL); | ||
75 | if (!new) | ||
76 | return NULL; | ||
77 | |||
78 | new->address = addr; | ||
79 | new->segment = segment; | ||
80 | new->start_bus = start; | ||
81 | new->end_bus = end; | ||
82 | |||
83 | list_add_sorted(new); | ||
84 | |||
85 | num_buses = end - start + 1; | ||
86 | res = &new->res; | ||
87 | res->start = addr + PCI_MMCFG_BUS_OFFSET(start); | ||
88 | res->end = addr + PCI_MMCFG_BUS_OFFSET(num_buses) - 1; | ||
89 | res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; | ||
90 | snprintf(new->name, PCI_MMCFG_RESOURCE_NAME_LEN, | ||
91 | "PCI MMCONFIG %04x [bus %02x-%02x]", segment, start, end); | ||
92 | res->name = new->name; | ||
93 | |||
94 | printk(KERN_INFO PREFIX "MMCONFIG for domain %04x [bus %02x-%02x] at " | ||
95 | "%pR (base %#lx)\n", segment, start, end, &new->res, | ||
96 | (unsigned long) addr); | ||
97 | |||
98 | return new; | ||
49 | } | 99 | } |
50 | 100 | ||
51 | static __init void fill_one_mmcfg(u64 addr, int segment, int start, int end) | 101 | struct pci_mmcfg_region *pci_mmconfig_lookup(int segment, int bus) |
52 | { | 102 | { |
53 | int i = pci_mmcfg_config_num; | 103 | struct pci_mmcfg_region *cfg; |
54 | 104 | ||
55 | pci_mmcfg_config_num++; | 105 | list_for_each_entry(cfg, &pci_mmcfg_list, list) |
56 | pci_mmcfg_config[i].address = addr; | 106 | if (cfg->segment == segment && |
57 | pci_mmcfg_config[i].pci_segment = segment; | 107 | cfg->start_bus <= bus && bus <= cfg->end_bus) |
58 | pci_mmcfg_config[i].start_bus_number = start; | 108 | return cfg; |
59 | pci_mmcfg_config[i].end_bus_number = end; | 109 | |
110 | return NULL; | ||
60 | } | 111 | } |
61 | 112 | ||
62 | static const char __init *pci_mmcfg_e7520(void) | 113 | static const char __init *pci_mmcfg_e7520(void) |
@@ -68,11 +119,9 @@ static const char __init *pci_mmcfg_e7520(void) | |||
68 | if (win == 0x0000 || win == 0xf000) | 119 | if (win == 0x0000 || win == 0xf000) |
69 | return NULL; | 120 | return NULL; |
70 | 121 | ||
71 | if (extend_mmcfg(1) == -1) | 122 | if (pci_mmconfig_add(0, 0, 255, win << 16) == NULL) |
72 | return NULL; | 123 | return NULL; |
73 | 124 | ||
74 | fill_one_mmcfg(win << 16, 0, 0, 255); | ||
75 | |||
76 | return "Intel Corporation E7520 Memory Controller Hub"; | 125 | return "Intel Corporation E7520 Memory Controller Hub"; |
77 | } | 126 | } |
78 | 127 | ||
@@ -114,11 +163,9 @@ static const char __init *pci_mmcfg_intel_945(void) | |||
114 | if ((pciexbar & mask) >= 0xf0000000U) | 163 | if ((pciexbar & mask) >= 0xf0000000U) |
115 | return NULL; | 164 | return NULL; |
116 | 165 | ||
117 | if (extend_mmcfg(1) == -1) | 166 | if (pci_mmconfig_add(0, 0, (len >> 20) - 1, pciexbar & mask) == NULL) |
118 | return NULL; | 167 | return NULL; |
119 | 168 | ||
120 | fill_one_mmcfg(pciexbar & mask, 0, 0, (len >> 20) - 1); | ||
121 | |||
122 | return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub"; | 169 | return "Intel Corporation 945G/GZ/P/PL Express Memory Controller Hub"; |
123 | } | 170 | } |
124 | 171 | ||
@@ -127,7 +174,7 @@ static const char __init *pci_mmcfg_amd_fam10h(void) | |||
127 | u32 low, high, address; | 174 | u32 low, high, address; |
128 | u64 base, msr; | 175 | u64 base, msr; |
129 | int i; | 176 | int i; |
130 | unsigned segnbits = 0, busnbits; | 177 | unsigned segnbits = 0, busnbits, end_bus; |
131 | 178 | ||
132 | if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF)) | 179 | if (!(pci_probe & PCI_CHECK_ENABLE_AMD_MMCONF)) |
133 | return NULL; | 180 | return NULL; |
@@ -161,11 +208,13 @@ static const char __init *pci_mmcfg_amd_fam10h(void) | |||
161 | busnbits = 8; | 208 | busnbits = 8; |
162 | } | 209 | } |
163 | 210 | ||
164 | if (extend_mmcfg(1 << segnbits) == -1) | 211 | end_bus = (1 << busnbits) - 1; |
165 | return NULL; | ||
166 | |||
167 | for (i = 0; i < (1 << segnbits); i++) | 212 | for (i = 0; i < (1 << segnbits); i++) |
168 | fill_one_mmcfg(base + (1<<28) * i, i, 0, (1 << busnbits) - 1); | 213 | if (pci_mmconfig_add(i, 0, end_bus, |
214 | base + (1<<28) * i) == NULL) { | ||
215 | free_all_mmcfg(); | ||
216 | return NULL; | ||
217 | } | ||
169 | 218 | ||
170 | return "AMD Family 10h NB"; | 219 | return "AMD Family 10h NB"; |
171 | } | 220 | } |
@@ -190,7 +239,7 @@ static const char __init *pci_mmcfg_nvidia_mcp55(void) | |||
190 | /* | 239 | /* |
191 | * do check if amd fam10h already took over | 240 | * do check if amd fam10h already took over |
192 | */ | 241 | */ |
193 | if (!acpi_disabled || pci_mmcfg_config_num || mcp55_checked) | 242 | if (!acpi_disabled || !list_empty(&pci_mmcfg_list) || mcp55_checked) |
194 | return NULL; | 243 | return NULL; |
195 | 244 | ||
196 | mcp55_checked = true; | 245 | mcp55_checked = true; |
@@ -213,16 +262,14 @@ static const char __init *pci_mmcfg_nvidia_mcp55(void) | |||
213 | if (!(extcfg & extcfg_enable_mask)) | 262 | if (!(extcfg & extcfg_enable_mask)) |
214 | continue; | 263 | continue; |
215 | 264 | ||
216 | if (extend_mmcfg(1) == -1) | ||
217 | continue; | ||
218 | |||
219 | size_index = (extcfg & extcfg_size_mask) >> extcfg_size_shift; | 265 | size_index = (extcfg & extcfg_size_mask) >> extcfg_size_shift; |
220 | base = extcfg & extcfg_base_mask[size_index]; | 266 | base = extcfg & extcfg_base_mask[size_index]; |
221 | /* base could > 4G */ | 267 | /* base could > 4G */ |
222 | base <<= extcfg_base_lshift; | 268 | base <<= extcfg_base_lshift; |
223 | start = (extcfg & extcfg_start_mask) >> extcfg_start_shift; | 269 | start = (extcfg & extcfg_start_mask) >> extcfg_start_shift; |
224 | end = start + extcfg_sizebus[size_index] - 1; | 270 | end = start + extcfg_sizebus[size_index] - 1; |
225 | fill_one_mmcfg(base, 0, start, end); | 271 | if (pci_mmconfig_add(0, start, end, base) == NULL) |
272 | continue; | ||
226 | mcp55_mmconf_found++; | 273 | mcp55_mmconf_found++; |
227 | } | 274 | } |
228 | 275 | ||
@@ -253,45 +300,22 @@ static struct pci_mmcfg_hostbridge_probe pci_mmcfg_probes[] __initdata = { | |||
253 | 0x0369, pci_mmcfg_nvidia_mcp55 }, | 300 | 0x0369, pci_mmcfg_nvidia_mcp55 }, |
254 | }; | 301 | }; |
255 | 302 | ||
256 | static int __init cmp_mmcfg(const void *x1, const void *x2) | ||
257 | { | ||
258 | const typeof(pci_mmcfg_config[0]) *m1 = x1; | ||
259 | const typeof(pci_mmcfg_config[0]) *m2 = x2; | ||
260 | int start1, start2; | ||
261 | |||
262 | start1 = m1->start_bus_number; | ||
263 | start2 = m2->start_bus_number; | ||
264 | |||
265 | return start1 - start2; | ||
266 | } | ||
267 | |||
268 | static void __init pci_mmcfg_check_end_bus_number(void) | 303 | static void __init pci_mmcfg_check_end_bus_number(void) |
269 | { | 304 | { |
270 | int i; | 305 | struct pci_mmcfg_region *cfg, *cfgx; |
271 | typeof(pci_mmcfg_config[0]) *cfg, *cfgx; | ||
272 | |||
273 | /* sort them at first */ | ||
274 | sort(pci_mmcfg_config, pci_mmcfg_config_num, | ||
275 | sizeof(pci_mmcfg_config[0]), cmp_mmcfg, NULL); | ||
276 | |||
277 | /* last one*/ | ||
278 | if (pci_mmcfg_config_num > 0) { | ||
279 | i = pci_mmcfg_config_num - 1; | ||
280 | cfg = &pci_mmcfg_config[i]; | ||
281 | if (cfg->end_bus_number < cfg->start_bus_number) | ||
282 | cfg->end_bus_number = 255; | ||
283 | } | ||
284 | 306 | ||
285 | /* don't overlap please */ | 307 | /* Fixup overlaps */ |
286 | for (i = 0; i < pci_mmcfg_config_num - 1; i++) { | 308 | list_for_each_entry(cfg, &pci_mmcfg_list, list) { |
287 | cfg = &pci_mmcfg_config[i]; | 309 | if (cfg->end_bus < cfg->start_bus) |
288 | cfgx = &pci_mmcfg_config[i+1]; | 310 | cfg->end_bus = 255; |
289 | 311 | ||
290 | if (cfg->end_bus_number < cfg->start_bus_number) | 312 | /* Don't access the list head ! */ |
291 | cfg->end_bus_number = 255; | 313 | if (cfg->list.next == &pci_mmcfg_list) |
314 | break; | ||
292 | 315 | ||
293 | if (cfg->end_bus_number >= cfgx->start_bus_number) | 316 | cfgx = list_entry(cfg->list.next, typeof(*cfg), list); |
294 | cfg->end_bus_number = cfgx->start_bus_number - 1; | 317 | if (cfg->end_bus >= cfgx->start_bus) |
318 | cfg->end_bus = cfgx->start_bus - 1; | ||
295 | } | 319 | } |
296 | } | 320 | } |
297 | 321 | ||
@@ -306,8 +330,7 @@ static int __init pci_mmcfg_check_hostbridge(void) | |||
306 | if (!raw_pci_ops) | 330 | if (!raw_pci_ops) |
307 | return 0; | 331 | return 0; |
308 | 332 | ||
309 | pci_mmcfg_config_num = 0; | 333 | free_all_mmcfg(); |
310 | pci_mmcfg_config = NULL; | ||
311 | 334 | ||
312 | for (i = 0; i < ARRAY_SIZE(pci_mmcfg_probes); i++) { | 335 | for (i = 0; i < ARRAY_SIZE(pci_mmcfg_probes); i++) { |
313 | bus = pci_mmcfg_probes[i].bus; | 336 | bus = pci_mmcfg_probes[i].bus; |
@@ -322,45 +345,22 @@ static int __init pci_mmcfg_check_hostbridge(void) | |||
322 | name = pci_mmcfg_probes[i].probe(); | 345 | name = pci_mmcfg_probes[i].probe(); |
323 | 346 | ||
324 | if (name) | 347 | if (name) |
325 | printk(KERN_INFO "PCI: Found %s with MMCONFIG support.\n", | 348 | printk(KERN_INFO PREFIX "%s with MMCONFIG support\n", |
326 | name); | 349 | name); |
327 | } | 350 | } |
328 | 351 | ||
329 | /* some end_bus_number is crazy, fix it */ | 352 | /* some end_bus_number is crazy, fix it */ |
330 | pci_mmcfg_check_end_bus_number(); | 353 | pci_mmcfg_check_end_bus_number(); |
331 | 354 | ||
332 | return pci_mmcfg_config_num != 0; | 355 | return !list_empty(&pci_mmcfg_list); |
333 | } | 356 | } |
334 | 357 | ||
335 | static void __init pci_mmcfg_insert_resources(void) | 358 | static void __init pci_mmcfg_insert_resources(void) |
336 | { | 359 | { |
337 | #define PCI_MMCFG_RESOURCE_NAME_LEN 24 | 360 | struct pci_mmcfg_region *cfg; |
338 | int i; | ||
339 | struct resource *res; | ||
340 | char *names; | ||
341 | unsigned num_buses; | ||
342 | |||
343 | res = kcalloc(PCI_MMCFG_RESOURCE_NAME_LEN + sizeof(*res), | ||
344 | pci_mmcfg_config_num, GFP_KERNEL); | ||
345 | if (!res) { | ||
346 | printk(KERN_ERR "PCI: Unable to allocate MMCONFIG resources\n"); | ||
347 | return; | ||
348 | } | ||
349 | 361 | ||
350 | names = (void *)&res[pci_mmcfg_config_num]; | 362 | list_for_each_entry(cfg, &pci_mmcfg_list, list) |
351 | for (i = 0; i < pci_mmcfg_config_num; i++, res++) { | 363 | insert_resource(&iomem_resource, &cfg->res); |
352 | struct acpi_mcfg_allocation *cfg = &pci_mmcfg_config[i]; | ||
353 | num_buses = cfg->end_bus_number - cfg->start_bus_number + 1; | ||
354 | res->name = names; | ||
355 | snprintf(names, PCI_MMCFG_RESOURCE_NAME_LEN, | ||
356 | "PCI MMCONFIG %u [%02x-%02x]", cfg->pci_segment, | ||
357 | cfg->start_bus_number, cfg->end_bus_number); | ||
358 | res->start = cfg->address + (cfg->start_bus_number << 20); | ||
359 | res->end = res->start + (num_buses << 20) - 1; | ||
360 | res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; | ||
361 | insert_resource(&iomem_resource, res); | ||
362 | names += PCI_MMCFG_RESOURCE_NAME_LEN; | ||
363 | } | ||
364 | 364 | ||
365 | /* Mark that the resources have been inserted. */ | 365 | /* Mark that the resources have been inserted. */ |
366 | pci_mmcfg_resources_inserted = 1; | 366 | pci_mmcfg_resources_inserted = 1; |
@@ -437,11 +437,12 @@ static int __init is_acpi_reserved(u64 start, u64 end, unsigned not_used) | |||
437 | typedef int (*check_reserved_t)(u64 start, u64 end, unsigned type); | 437 | typedef int (*check_reserved_t)(u64 start, u64 end, unsigned type); |
438 | 438 | ||
439 | static int __init is_mmconf_reserved(check_reserved_t is_reserved, | 439 | static int __init is_mmconf_reserved(check_reserved_t is_reserved, |
440 | u64 addr, u64 size, int i, | 440 | struct pci_mmcfg_region *cfg, int with_e820) |
441 | typeof(pci_mmcfg_config[0]) *cfg, int with_e820) | ||
442 | { | 441 | { |
442 | u64 addr = cfg->res.start; | ||
443 | u64 size = resource_size(&cfg->res); | ||
443 | u64 old_size = size; | 444 | u64 old_size = size; |
444 | int valid = 0; | 445 | int valid = 0, num_buses; |
445 | 446 | ||
446 | while (!is_reserved(addr, addr + size, E820_RESERVED)) { | 447 | while (!is_reserved(addr, addr + size, E820_RESERVED)) { |
447 | size >>= 1; | 448 | size >>= 1; |
@@ -450,19 +451,25 @@ static int __init is_mmconf_reserved(check_reserved_t is_reserved, | |||
450 | } | 451 | } |
451 | 452 | ||
452 | if (size >= (16UL<<20) || size == old_size) { | 453 | if (size >= (16UL<<20) || size == old_size) { |
453 | printk(KERN_NOTICE | 454 | printk(KERN_INFO PREFIX "MMCONFIG at %pR reserved in %s\n", |
454 | "PCI: MCFG area at %Lx reserved in %s\n", | 455 | &cfg->res, |
455 | addr, with_e820?"E820":"ACPI motherboard resources"); | 456 | with_e820 ? "E820" : "ACPI motherboard resources"); |
456 | valid = 1; | 457 | valid = 1; |
457 | 458 | ||
458 | if (old_size != size) { | 459 | if (old_size != size) { |
459 | /* update end_bus_number */ | 460 | /* update end_bus */ |
460 | cfg->end_bus_number = cfg->start_bus_number + ((size>>20) - 1); | 461 | cfg->end_bus = cfg->start_bus + ((size>>20) - 1); |
461 | printk(KERN_NOTICE "PCI: updated MCFG configuration %d: base %lx " | 462 | num_buses = cfg->end_bus - cfg->start_bus + 1; |
462 | "segment %hu buses %u - %u\n", | 463 | cfg->res.end = cfg->res.start + |
463 | i, (unsigned long)cfg->address, cfg->pci_segment, | 464 | PCI_MMCFG_BUS_OFFSET(num_buses) - 1; |
464 | (unsigned int)cfg->start_bus_number, | 465 | snprintf(cfg->name, PCI_MMCFG_RESOURCE_NAME_LEN, |
465 | (unsigned int)cfg->end_bus_number); | 466 | "PCI MMCONFIG %04x [bus %02x-%02x]", |
467 | cfg->segment, cfg->start_bus, cfg->end_bus); | ||
468 | printk(KERN_INFO PREFIX | ||
469 | "MMCONFIG for %04x [bus%02x-%02x] " | ||
470 | "at %pR (base %#lx) (size reduced!)\n", | ||
471 | cfg->segment, cfg->start_bus, cfg->end_bus, | ||
472 | &cfg->res, (unsigned long) cfg->address); | ||
466 | } | 473 | } |
467 | } | 474 | } |
468 | 475 | ||
@@ -471,45 +478,26 @@ static int __init is_mmconf_reserved(check_reserved_t is_reserved, | |||
471 | 478 | ||
472 | static void __init pci_mmcfg_reject_broken(int early) | 479 | static void __init pci_mmcfg_reject_broken(int early) |
473 | { | 480 | { |
474 | typeof(pci_mmcfg_config[0]) *cfg; | 481 | struct pci_mmcfg_region *cfg; |
475 | int i; | ||
476 | 482 | ||
477 | if ((pci_mmcfg_config_num == 0) || | 483 | list_for_each_entry(cfg, &pci_mmcfg_list, list) { |
478 | (pci_mmcfg_config == NULL) || | ||
479 | (pci_mmcfg_config[0].address == 0)) | ||
480 | return; | ||
481 | |||
482 | for (i = 0; i < pci_mmcfg_config_num; i++) { | ||
483 | int valid = 0; | 484 | int valid = 0; |
484 | u64 addr, size; | ||
485 | |||
486 | cfg = &pci_mmcfg_config[i]; | ||
487 | addr = cfg->start_bus_number; | ||
488 | addr <<= 20; | ||
489 | addr += cfg->address; | ||
490 | size = cfg->end_bus_number + 1 - cfg->start_bus_number; | ||
491 | size <<= 20; | ||
492 | printk(KERN_NOTICE "PCI: MCFG configuration %d: base %lx " | ||
493 | "segment %hu buses %u - %u\n", | ||
494 | i, (unsigned long)cfg->address, cfg->pci_segment, | ||
495 | (unsigned int)cfg->start_bus_number, | ||
496 | (unsigned int)cfg->end_bus_number); | ||
497 | 485 | ||
498 | if (!early && !acpi_disabled) | 486 | if (!early && !acpi_disabled) |
499 | valid = is_mmconf_reserved(is_acpi_reserved, addr, size, i, cfg, 0); | 487 | valid = is_mmconf_reserved(is_acpi_reserved, cfg, 0); |
500 | 488 | ||
501 | if (valid) | 489 | if (valid) |
502 | continue; | 490 | continue; |
503 | 491 | ||
504 | if (!early) | 492 | if (!early) |
505 | printk(KERN_ERR "PCI: BIOS Bug: MCFG area at %Lx is not" | 493 | printk(KERN_ERR FW_BUG PREFIX |
506 | " reserved in ACPI motherboard resources\n", | 494 | "MMCONFIG at %pR not reserved in " |
507 | cfg->address); | 495 | "ACPI motherboard resources\n", &cfg->res); |
508 | 496 | ||
509 | /* Don't try to do this check unless configuration | 497 | /* Don't try to do this check unless configuration |
510 | type 1 is available. how about type 2 ?*/ | 498 | type 1 is available. how about type 2 ?*/ |
511 | if (raw_pci_ops) | 499 | if (raw_pci_ops) |
512 | valid = is_mmconf_reserved(e820_all_mapped, addr, size, i, cfg, 1); | 500 | valid = is_mmconf_reserved(e820_all_mapped, cfg, 1); |
513 | 501 | ||
514 | if (!valid) | 502 | if (!valid) |
515 | goto reject; | 503 | goto reject; |
@@ -518,34 +506,41 @@ static void __init pci_mmcfg_reject_broken(int early) | |||
518 | return; | 506 | return; |
519 | 507 | ||
520 | reject: | 508 | reject: |
521 | printk(KERN_INFO "PCI: Not using MMCONFIG.\n"); | 509 | printk(KERN_INFO PREFIX "not using MMCONFIG\n"); |
522 | pci_mmcfg_arch_free(); | 510 | free_all_mmcfg(); |
523 | kfree(pci_mmcfg_config); | ||
524 | pci_mmcfg_config = NULL; | ||
525 | pci_mmcfg_config_num = 0; | ||
526 | } | 511 | } |
527 | 512 | ||
528 | static int __initdata known_bridge; | 513 | static int __initdata known_bridge; |
529 | 514 | ||
530 | static int acpi_mcfg_64bit_base_addr __initdata = FALSE; | 515 | static int __init acpi_mcfg_check_entry(struct acpi_table_mcfg *mcfg, |
516 | struct acpi_mcfg_allocation *cfg) | ||
517 | { | ||
518 | int year; | ||
531 | 519 | ||
532 | /* The physical address of the MMCONFIG aperture. Set from ACPI tables. */ | 520 | if (cfg->address < 0xFFFFFFFF) |
533 | struct acpi_mcfg_allocation *pci_mmcfg_config; | 521 | return 0; |
534 | int pci_mmcfg_config_num; | ||
535 | 522 | ||
536 | static int __init acpi_mcfg_oem_check(struct acpi_table_mcfg *mcfg) | ||
537 | { | ||
538 | if (!strcmp(mcfg->header.oem_id, "SGI")) | 523 | if (!strcmp(mcfg->header.oem_id, "SGI")) |
539 | acpi_mcfg_64bit_base_addr = TRUE; | 524 | return 0; |
540 | 525 | ||
541 | return 0; | 526 | if (mcfg->header.revision >= 1) { |
527 | if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && | ||
528 | year >= 2010) | ||
529 | return 0; | ||
530 | } | ||
531 | |||
532 | printk(KERN_ERR PREFIX "MCFG region for %04x [bus %02x-%02x] at %#llx " | ||
533 | "is above 4GB, ignored\n", cfg->pci_segment, | ||
534 | cfg->start_bus_number, cfg->end_bus_number, cfg->address); | ||
535 | return -EINVAL; | ||
542 | } | 536 | } |
543 | 537 | ||
544 | static int __init pci_parse_mcfg(struct acpi_table_header *header) | 538 | static int __init pci_parse_mcfg(struct acpi_table_header *header) |
545 | { | 539 | { |
546 | struct acpi_table_mcfg *mcfg; | 540 | struct acpi_table_mcfg *mcfg; |
541 | struct acpi_mcfg_allocation *cfg_table, *cfg; | ||
547 | unsigned long i; | 542 | unsigned long i; |
548 | int config_size; | 543 | int entries; |
549 | 544 | ||
550 | if (!header) | 545 | if (!header) |
551 | return -EINVAL; | 546 | return -EINVAL; |
@@ -553,38 +548,33 @@ static int __init pci_parse_mcfg(struct acpi_table_header *header) | |||
553 | mcfg = (struct acpi_table_mcfg *)header; | 548 | mcfg = (struct acpi_table_mcfg *)header; |
554 | 549 | ||
555 | /* how many config structures do we have */ | 550 | /* how many config structures do we have */ |
556 | pci_mmcfg_config_num = 0; | 551 | free_all_mmcfg(); |
552 | entries = 0; | ||
557 | i = header->length - sizeof(struct acpi_table_mcfg); | 553 | i = header->length - sizeof(struct acpi_table_mcfg); |
558 | while (i >= sizeof(struct acpi_mcfg_allocation)) { | 554 | while (i >= sizeof(struct acpi_mcfg_allocation)) { |
559 | ++pci_mmcfg_config_num; | 555 | entries++; |
560 | i -= sizeof(struct acpi_mcfg_allocation); | 556 | i -= sizeof(struct acpi_mcfg_allocation); |
561 | }; | 557 | }; |
562 | if (pci_mmcfg_config_num == 0) { | 558 | if (entries == 0) { |
563 | printk(KERN_ERR PREFIX "MMCONFIG has no entries\n"); | 559 | printk(KERN_ERR PREFIX "MMCONFIG has no entries\n"); |
564 | return -ENODEV; | 560 | return -ENODEV; |
565 | } | 561 | } |
566 | 562 | ||
567 | config_size = pci_mmcfg_config_num * sizeof(*pci_mmcfg_config); | 563 | cfg_table = (struct acpi_mcfg_allocation *) &mcfg[1]; |
568 | pci_mmcfg_config = kmalloc(config_size, GFP_KERNEL); | 564 | for (i = 0; i < entries; i++) { |
569 | if (!pci_mmcfg_config) { | 565 | cfg = &cfg_table[i]; |
570 | printk(KERN_WARNING PREFIX | 566 | if (acpi_mcfg_check_entry(mcfg, cfg)) { |
571 | "No memory for MCFG config tables\n"); | 567 | free_all_mmcfg(); |
572 | return -ENOMEM; | ||
573 | } | ||
574 | |||
575 | memcpy(pci_mmcfg_config, &mcfg[1], config_size); | ||
576 | |||
577 | acpi_mcfg_oem_check(mcfg); | ||
578 | |||
579 | for (i = 0; i < pci_mmcfg_config_num; ++i) { | ||
580 | if ((pci_mmcfg_config[i].address > 0xFFFFFFFF) && | ||
581 | !acpi_mcfg_64bit_base_addr) { | ||
582 | printk(KERN_ERR PREFIX | ||
583 | "MMCONFIG not in low 4GB of memory\n"); | ||
584 | kfree(pci_mmcfg_config); | ||
585 | pci_mmcfg_config_num = 0; | ||
586 | return -ENODEV; | 568 | return -ENODEV; |
587 | } | 569 | } |
570 | |||
571 | if (pci_mmconfig_add(cfg->pci_segment, cfg->start_bus_number, | ||
572 | cfg->end_bus_number, cfg->address) == NULL) { | ||
573 | printk(KERN_WARNING PREFIX | ||
574 | "no memory for MCFG entries\n"); | ||
575 | free_all_mmcfg(); | ||
576 | return -ENOMEM; | ||
577 | } | ||
588 | } | 578 | } |
589 | 579 | ||
590 | return 0; | 580 | return 0; |
@@ -614,9 +604,7 @@ static void __init __pci_mmcfg_init(int early) | |||
614 | 604 | ||
615 | pci_mmcfg_reject_broken(early); | 605 | pci_mmcfg_reject_broken(early); |
616 | 606 | ||
617 | if ((pci_mmcfg_config_num == 0) || | 607 | if (list_empty(&pci_mmcfg_list)) |
618 | (pci_mmcfg_config == NULL) || | ||
619 | (pci_mmcfg_config[0].address == 0)) | ||
620 | return; | 608 | return; |
621 | 609 | ||
622 | if (pci_mmcfg_arch_init()) | 610 | if (pci_mmcfg_arch_init()) |
@@ -648,9 +636,7 @@ static int __init pci_mmcfg_late_insert_resources(void) | |||
648 | */ | 636 | */ |
649 | if ((pci_mmcfg_resources_inserted == 1) || | 637 | if ((pci_mmcfg_resources_inserted == 1) || |
650 | (pci_probe & PCI_PROBE_MMCONF) == 0 || | 638 | (pci_probe & PCI_PROBE_MMCONF) == 0 || |
651 | (pci_mmcfg_config_num == 0) || | 639 | list_empty(&pci_mmcfg_list)) |
652 | (pci_mmcfg_config == NULL) || | ||
653 | (pci_mmcfg_config[0].address == 0)) | ||
654 | return 1; | 640 | return 1; |
655 | 641 | ||
656 | /* | 642 | /* |
diff --git a/arch/x86/pci/mmconfig_32.c b/arch/x86/pci/mmconfig_32.c index f10a7e94a84c..90d5fd476ed4 100644 --- a/arch/x86/pci/mmconfig_32.c +++ b/arch/x86/pci/mmconfig_32.c | |||
@@ -27,18 +27,10 @@ static int mmcfg_last_accessed_cpu; | |||
27 | */ | 27 | */ |
28 | static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn) | 28 | static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn) |
29 | { | 29 | { |
30 | struct acpi_mcfg_allocation *cfg; | 30 | struct pci_mmcfg_region *cfg = pci_mmconfig_lookup(seg, bus); |
31 | int cfg_num; | ||
32 | |||
33 | for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) { | ||
34 | cfg = &pci_mmcfg_config[cfg_num]; | ||
35 | if (cfg->pci_segment == seg && | ||
36 | (cfg->start_bus_number <= bus) && | ||
37 | (cfg->end_bus_number >= bus)) | ||
38 | return cfg->address; | ||
39 | } | ||
40 | 31 | ||
41 | /* Fall back to type 0 */ | 32 | if (cfg) |
33 | return cfg->address; | ||
42 | return 0; | 34 | return 0; |
43 | } | 35 | } |
44 | 36 | ||
@@ -47,7 +39,7 @@ static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn) | |||
47 | */ | 39 | */ |
48 | static void pci_exp_set_dev_base(unsigned int base, int bus, int devfn) | 40 | static void pci_exp_set_dev_base(unsigned int base, int bus, int devfn) |
49 | { | 41 | { |
50 | u32 dev_base = base | (bus << 20) | (devfn << 12); | 42 | u32 dev_base = base | PCI_MMCFG_BUS_OFFSET(bus) | (devfn << 12); |
51 | int cpu = smp_processor_id(); | 43 | int cpu = smp_processor_id(); |
52 | if (dev_base != mmcfg_last_accessed_device || | 44 | if (dev_base != mmcfg_last_accessed_device || |
53 | cpu != mmcfg_last_accessed_cpu) { | 45 | cpu != mmcfg_last_accessed_cpu) { |
diff --git a/arch/x86/pci/mmconfig_64.c b/arch/x86/pci/mmconfig_64.c index 94349f8b2f96..e783841bd1d7 100644 --- a/arch/x86/pci/mmconfig_64.c +++ b/arch/x86/pci/mmconfig_64.c | |||
@@ -12,38 +12,15 @@ | |||
12 | #include <asm/e820.h> | 12 | #include <asm/e820.h> |
13 | #include <asm/pci_x86.h> | 13 | #include <asm/pci_x86.h> |
14 | 14 | ||
15 | /* Static virtual mapping of the MMCONFIG aperture */ | 15 | #define PREFIX "PCI: " |
16 | struct mmcfg_virt { | ||
17 | struct acpi_mcfg_allocation *cfg; | ||
18 | char __iomem *virt; | ||
19 | }; | ||
20 | static struct mmcfg_virt *pci_mmcfg_virt; | ||
21 | |||
22 | static char __iomem *get_virt(unsigned int seg, unsigned bus) | ||
23 | { | ||
24 | struct acpi_mcfg_allocation *cfg; | ||
25 | int cfg_num; | ||
26 | |||
27 | for (cfg_num = 0; cfg_num < pci_mmcfg_config_num; cfg_num++) { | ||
28 | cfg = pci_mmcfg_virt[cfg_num].cfg; | ||
29 | if (cfg->pci_segment == seg && | ||
30 | (cfg->start_bus_number <= bus) && | ||
31 | (cfg->end_bus_number >= bus)) | ||
32 | return pci_mmcfg_virt[cfg_num].virt; | ||
33 | } | ||
34 | |||
35 | /* Fall back to type 0 */ | ||
36 | return NULL; | ||
37 | } | ||
38 | 16 | ||
39 | static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn) | 17 | static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn) |
40 | { | 18 | { |
41 | char __iomem *addr; | 19 | struct pci_mmcfg_region *cfg = pci_mmconfig_lookup(seg, bus); |
42 | 20 | ||
43 | addr = get_virt(seg, bus); | 21 | if (cfg && cfg->virt) |
44 | if (!addr) | 22 | return cfg->virt + (PCI_MMCFG_BUS_OFFSET(bus) | (devfn << 12)); |
45 | return NULL; | 23 | return NULL; |
46 | return addr + ((bus << 20) | (devfn << 12)); | ||
47 | } | 24 | } |
48 | 25 | ||
49 | static int pci_mmcfg_read(unsigned int seg, unsigned int bus, | 26 | static int pci_mmcfg_read(unsigned int seg, unsigned int bus, |
@@ -109,42 +86,30 @@ static struct pci_raw_ops pci_mmcfg = { | |||
109 | .write = pci_mmcfg_write, | 86 | .write = pci_mmcfg_write, |
110 | }; | 87 | }; |
111 | 88 | ||
112 | static void __iomem * __init mcfg_ioremap(struct acpi_mcfg_allocation *cfg) | 89 | static void __iomem * __init mcfg_ioremap(struct pci_mmcfg_region *cfg) |
113 | { | 90 | { |
114 | void __iomem *addr; | 91 | void __iomem *addr; |
115 | u64 start, size; | 92 | u64 start, size; |
93 | int num_buses; | ||
116 | 94 | ||
117 | start = cfg->start_bus_number; | 95 | start = cfg->address + PCI_MMCFG_BUS_OFFSET(cfg->start_bus); |
118 | start <<= 20; | 96 | num_buses = cfg->end_bus - cfg->start_bus + 1; |
119 | start += cfg->address; | 97 | size = PCI_MMCFG_BUS_OFFSET(num_buses); |
120 | size = cfg->end_bus_number + 1 - cfg->start_bus_number; | ||
121 | size <<= 20; | ||
122 | addr = ioremap_nocache(start, size); | 98 | addr = ioremap_nocache(start, size); |
123 | if (addr) { | 99 | if (addr) |
124 | printk(KERN_INFO "PCI: Using MMCONFIG at %Lx - %Lx\n", | 100 | addr -= PCI_MMCFG_BUS_OFFSET(cfg->start_bus); |
125 | start, start + size - 1); | ||
126 | addr -= cfg->start_bus_number << 20; | ||
127 | } | ||
128 | return addr; | 101 | return addr; |
129 | } | 102 | } |
130 | 103 | ||
131 | int __init pci_mmcfg_arch_init(void) | 104 | int __init pci_mmcfg_arch_init(void) |
132 | { | 105 | { |
133 | int i; | 106 | struct pci_mmcfg_region *cfg; |
134 | pci_mmcfg_virt = kzalloc(sizeof(*pci_mmcfg_virt) * | ||
135 | pci_mmcfg_config_num, GFP_KERNEL); | ||
136 | if (pci_mmcfg_virt == NULL) { | ||
137 | printk(KERN_ERR "PCI: Can not allocate memory for mmconfig structures\n"); | ||
138 | return 0; | ||
139 | } | ||
140 | 107 | ||
141 | for (i = 0; i < pci_mmcfg_config_num; ++i) { | 108 | list_for_each_entry(cfg, &pci_mmcfg_list, list) { |
142 | pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i]; | 109 | cfg->virt = mcfg_ioremap(cfg); |
143 | pci_mmcfg_virt[i].virt = mcfg_ioremap(&pci_mmcfg_config[i]); | 110 | if (!cfg->virt) { |
144 | if (!pci_mmcfg_virt[i].virt) { | 111 | printk(KERN_ERR PREFIX "can't map MMCONFIG at %pR\n", |
145 | printk(KERN_ERR "PCI: Cannot map mmconfig aperture for " | 112 | &cfg->res); |
146 | "segment %d\n", | ||
147 | pci_mmcfg_config[i].pci_segment); | ||
148 | pci_mmcfg_arch_free(); | 113 | pci_mmcfg_arch_free(); |
149 | return 0; | 114 | return 0; |
150 | } | 115 | } |
@@ -155,19 +120,12 @@ int __init pci_mmcfg_arch_init(void) | |||
155 | 120 | ||
156 | void __init pci_mmcfg_arch_free(void) | 121 | void __init pci_mmcfg_arch_free(void) |
157 | { | 122 | { |
158 | int i; | 123 | struct pci_mmcfg_region *cfg; |
159 | |||
160 | if (pci_mmcfg_virt == NULL) | ||
161 | return; | ||
162 | 124 | ||
163 | for (i = 0; i < pci_mmcfg_config_num; ++i) { | 125 | list_for_each_entry(cfg, &pci_mmcfg_list, list) { |
164 | if (pci_mmcfg_virt[i].virt) { | 126 | if (cfg->virt) { |
165 | iounmap(pci_mmcfg_virt[i].virt + (pci_mmcfg_virt[i].cfg->start_bus_number << 20)); | 127 | iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus)); |
166 | pci_mmcfg_virt[i].virt = NULL; | 128 | cfg->virt = NULL; |
167 | pci_mmcfg_virt[i].cfg = NULL; | ||
168 | } | 129 | } |
169 | } | 130 | } |
170 | |||
171 | kfree(pci_mmcfg_virt); | ||
172 | pci_mmcfg_virt = NULL; | ||
173 | } | 131 | } |
diff --git a/arch/x86/pci/mrst.c b/arch/x86/pci/mrst.c new file mode 100644 index 000000000000..1cdc02cf8fa4 --- /dev/null +++ b/arch/x86/pci/mrst.c | |||
@@ -0,0 +1,266 @@ | |||
1 | /* | ||
2 | * Moorestown PCI support | ||
3 | * Copyright (c) 2008 Intel Corporation | ||
4 | * Jesse Barnes <jesse.barnes@intel.com> | ||
5 | * | ||
6 | * Moorestown has an interesting PCI implementation: | ||
7 | * - configuration space is memory mapped (as defined by MCFG) | ||
8 | * - Lincroft devices also have a real, type 1 configuration space | ||
9 | * - Early Lincroft silicon has a type 1 access bug that will cause | ||
10 | * a hang if non-existent devices are accessed | ||
11 | * - some devices have the "fixed BAR" capability, which means | ||
12 | * they can't be relocated or modified; check for that during | ||
13 | * BAR sizing | ||
14 | * | ||
15 | * So, we use the MCFG space for all reads and writes, but also send | ||
16 | * Lincroft writes to type 1 space. But only read/write if the device | ||
17 | * actually exists, otherwise return all 1s for reads and bit bucket | ||
18 | * the writes. | ||
19 | */ | ||
20 | |||
21 | #include <linux/sched.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <linux/ioport.h> | ||
24 | #include <linux/init.h> | ||
25 | #include <linux/dmi.h> | ||
26 | |||
27 | #include <asm/acpi.h> | ||
28 | #include <asm/segment.h> | ||
29 | #include <asm/io.h> | ||
30 | #include <asm/smp.h> | ||
31 | #include <asm/pci_x86.h> | ||
32 | #include <asm/hw_irq.h> | ||
33 | #include <asm/io_apic.h> | ||
34 | |||
35 | #define PCIE_CAP_OFFSET 0x100 | ||
36 | |||
37 | /* Fixed BAR fields */ | ||
38 | #define PCIE_VNDR_CAP_ID_FIXED_BAR 0x00 /* Fixed BAR (TBD) */ | ||
39 | #define PCI_FIXED_BAR_0_SIZE 0x04 | ||
40 | #define PCI_FIXED_BAR_1_SIZE 0x08 | ||
41 | #define PCI_FIXED_BAR_2_SIZE 0x0c | ||
42 | #define PCI_FIXED_BAR_3_SIZE 0x10 | ||
43 | #define PCI_FIXED_BAR_4_SIZE 0x14 | ||
44 | #define PCI_FIXED_BAR_5_SIZE 0x1c | ||
45 | |||
46 | /** | ||
47 | * fixed_bar_cap - return the offset of the fixed BAR cap if found | ||
48 | * @bus: PCI bus | ||
49 | * @devfn: device in question | ||
50 | * | ||
51 | * Look for the fixed BAR cap on @bus and @devfn, returning its offset | ||
52 | * if found or 0 otherwise. | ||
53 | */ | ||
54 | static int fixed_bar_cap(struct pci_bus *bus, unsigned int devfn) | ||
55 | { | ||
56 | int pos; | ||
57 | u32 pcie_cap = 0, cap_data; | ||
58 | |||
59 | pos = PCIE_CAP_OFFSET; | ||
60 | |||
61 | if (!raw_pci_ext_ops) | ||
62 | return 0; | ||
63 | |||
64 | while (pos) { | ||
65 | if (raw_pci_ext_ops->read(pci_domain_nr(bus), bus->number, | ||
66 | devfn, pos, 4, &pcie_cap)) | ||
67 | return 0; | ||
68 | |||
69 | if (pcie_cap == 0xffffffff) | ||
70 | return 0; | ||
71 | |||
72 | if (PCI_EXT_CAP_ID(pcie_cap) == PCI_EXT_CAP_ID_VNDR) { | ||
73 | raw_pci_ext_ops->read(pci_domain_nr(bus), bus->number, | ||
74 | devfn, pos + 4, 4, &cap_data); | ||
75 | if ((cap_data & 0xffff) == PCIE_VNDR_CAP_ID_FIXED_BAR) | ||
76 | return pos; | ||
77 | } | ||
78 | |||
79 | pos = pcie_cap >> 20; | ||
80 | } | ||
81 | |||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static int pci_device_update_fixed(struct pci_bus *bus, unsigned int devfn, | ||
86 | int reg, int len, u32 val, int offset) | ||
87 | { | ||
88 | u32 size; | ||
89 | unsigned int domain, busnum; | ||
90 | int bar = (reg - PCI_BASE_ADDRESS_0) >> 2; | ||
91 | |||
92 | domain = pci_domain_nr(bus); | ||
93 | busnum = bus->number; | ||
94 | |||
95 | if (val == ~0 && len == 4) { | ||
96 | unsigned long decode; | ||
97 | |||
98 | raw_pci_ext_ops->read(domain, busnum, devfn, | ||
99 | offset + 8 + (bar * 4), 4, &size); | ||
100 | |||
101 | /* Turn the size into a decode pattern for the sizing code */ | ||
102 | if (size) { | ||
103 | decode = size - 1; | ||
104 | decode |= decode >> 1; | ||
105 | decode |= decode >> 2; | ||
106 | decode |= decode >> 4; | ||
107 | decode |= decode >> 8; | ||
108 | decode |= decode >> 16; | ||
109 | decode++; | ||
110 | decode = ~(decode - 1); | ||
111 | } else { | ||
112 | decode = ~0; | ||
113 | } | ||
114 | |||
115 | /* | ||
116 | * If val is all ones, the core code is trying to size the reg, | ||
117 | * so update the mmconfig space with the real size. | ||
118 | * | ||
119 | * Note: this assumes the fixed size we got is a power of two. | ||
120 | */ | ||
121 | return raw_pci_ext_ops->write(domain, busnum, devfn, reg, 4, | ||
122 | decode); | ||
123 | } | ||
124 | |||
125 | /* This is some other kind of BAR write, so just do it. */ | ||
126 | return raw_pci_ext_ops->write(domain, busnum, devfn, reg, len, val); | ||
127 | } | ||
128 | |||
129 | /** | ||
130 | * type1_access_ok - check whether to use type 1 | ||
131 | * @bus: bus number | ||
132 | * @devfn: device & function in question | ||
133 | * | ||
134 | * If the bus is on a Lincroft chip and it exists, or is not on a Lincroft at | ||
135 | * all, the we can go ahead with any reads & writes. If it's on a Lincroft, | ||
136 | * but doesn't exist, avoid the access altogether to keep the chip from | ||
137 | * hanging. | ||
138 | */ | ||
139 | static bool type1_access_ok(unsigned int bus, unsigned int devfn, int reg) | ||
140 | { | ||
141 | /* This is a workaround for A0 LNC bug where PCI status register does | ||
142 | * not have new CAP bit set. can not be written by SW either. | ||
143 | * | ||
144 | * PCI header type in real LNC indicates a single function device, this | ||
145 | * will prevent probing other devices under the same function in PCI | ||
146 | * shim. Therefore, use the header type in shim instead. | ||
147 | */ | ||
148 | if (reg >= 0x100 || reg == PCI_STATUS || reg == PCI_HEADER_TYPE) | ||
149 | return 0; | ||
150 | if (bus == 0 && (devfn == PCI_DEVFN(2, 0) || devfn == PCI_DEVFN(0, 0))) | ||
151 | return 1; | ||
152 | return 0; /* langwell on others */ | ||
153 | } | ||
154 | |||
155 | static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, | ||
156 | int size, u32 *value) | ||
157 | { | ||
158 | if (type1_access_ok(bus->number, devfn, where)) | ||
159 | return pci_direct_conf1.read(pci_domain_nr(bus), bus->number, | ||
160 | devfn, where, size, value); | ||
161 | return raw_pci_ext_ops->read(pci_domain_nr(bus), bus->number, | ||
162 | devfn, where, size, value); | ||
163 | } | ||
164 | |||
165 | static int pci_write(struct pci_bus *bus, unsigned int devfn, int where, | ||
166 | int size, u32 value) | ||
167 | { | ||
168 | int offset; | ||
169 | |||
170 | /* On MRST, there is no PCI ROM BAR, this will cause a subsequent read | ||
171 | * to ROM BAR return 0 then being ignored. | ||
172 | */ | ||
173 | if (where == PCI_ROM_ADDRESS) | ||
174 | return 0; | ||
175 | |||
176 | /* | ||
177 | * Devices with fixed BARs need special handling: | ||
178 | * - BAR sizing code will save, write ~0, read size, restore | ||
179 | * - so writes to fixed BARs need special handling | ||
180 | * - other writes to fixed BAR devices should go through mmconfig | ||
181 | */ | ||
182 | offset = fixed_bar_cap(bus, devfn); | ||
183 | if (offset && | ||
184 | (where >= PCI_BASE_ADDRESS_0 && where <= PCI_BASE_ADDRESS_5)) { | ||
185 | return pci_device_update_fixed(bus, devfn, where, size, value, | ||
186 | offset); | ||
187 | } | ||
188 | |||
189 | /* | ||
190 | * On Moorestown update both real & mmconfig space | ||
191 | * Note: early Lincroft silicon can't handle type 1 accesses to | ||
192 | * non-existent devices, so just eat the write in that case. | ||
193 | */ | ||
194 | if (type1_access_ok(bus->number, devfn, where)) | ||
195 | return pci_direct_conf1.write(pci_domain_nr(bus), bus->number, | ||
196 | devfn, where, size, value); | ||
197 | return raw_pci_ext_ops->write(pci_domain_nr(bus), bus->number, devfn, | ||
198 | where, size, value); | ||
199 | } | ||
200 | |||
201 | static int mrst_pci_irq_enable(struct pci_dev *dev) | ||
202 | { | ||
203 | u8 pin; | ||
204 | struct io_apic_irq_attr irq_attr; | ||
205 | |||
206 | pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); | ||
207 | |||
208 | /* MRST only have IOAPIC, the PCI irq lines are 1:1 mapped to | ||
209 | * IOAPIC RTE entries, so we just enable RTE for the device. | ||
210 | */ | ||
211 | irq_attr.ioapic = mp_find_ioapic(dev->irq); | ||
212 | irq_attr.ioapic_pin = dev->irq; | ||
213 | irq_attr.trigger = 1; /* level */ | ||
214 | irq_attr.polarity = 1; /* active low */ | ||
215 | io_apic_set_pci_routing(&dev->dev, dev->irq, &irq_attr); | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | struct pci_ops pci_mrst_ops = { | ||
221 | .read = pci_read, | ||
222 | .write = pci_write, | ||
223 | }; | ||
224 | |||
225 | /** | ||
226 | * pci_mrst_init - installs pci_mrst_ops | ||
227 | * | ||
228 | * Moorestown has an interesting PCI implementation (see above). | ||
229 | * Called when the early platform detection installs it. | ||
230 | */ | ||
231 | int __init pci_mrst_init(void) | ||
232 | { | ||
233 | printk(KERN_INFO "Moorestown platform detected, using MRST PCI ops\n"); | ||
234 | pci_mmcfg_late_init(); | ||
235 | pcibios_enable_irq = mrst_pci_irq_enable; | ||
236 | pci_root_ops = pci_mrst_ops; | ||
237 | /* Continue with standard init */ | ||
238 | return 1; | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | * Langwell devices reside at fixed offsets, don't try to move them. | ||
243 | */ | ||
244 | static void __devinit pci_fixed_bar_fixup(struct pci_dev *dev) | ||
245 | { | ||
246 | unsigned long offset; | ||
247 | u32 size; | ||
248 | int i; | ||
249 | |||
250 | /* Must have extended configuration space */ | ||
251 | if (dev->cfg_size < PCIE_CAP_OFFSET + 4) | ||
252 | return; | ||
253 | |||
254 | /* Fixup the BAR sizes for fixed BAR devices and make them unmoveable */ | ||
255 | offset = fixed_bar_cap(dev->bus, dev->devfn); | ||
256 | if (!offset || PCI_DEVFN(2, 0) == dev->devfn || | ||
257 | PCI_DEVFN(2, 2) == dev->devfn) | ||
258 | return; | ||
259 | |||
260 | for (i = 0; i < PCI_ROM_RESOURCE; i++) { | ||
261 | pci_read_config_dword(dev, offset + 8 + (i * 4), &size); | ||
262 | dev->resource[i].end = dev->resource[i].start + size - 1; | ||
263 | dev->resource[i].flags |= IORESOURCE_PCI_FIXED; | ||
264 | } | ||
265 | } | ||
266 | DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_fixed_bar_fixup); | ||
diff --git a/arch/x86/pci/numaq_32.c b/arch/x86/pci/numaq_32.c index 8eb295e116f6..8223738ad806 100644 --- a/arch/x86/pci/numaq_32.c +++ b/arch/x86/pci/numaq_32.c | |||
@@ -8,9 +8,7 @@ | |||
8 | #include <asm/apic.h> | 8 | #include <asm/apic.h> |
9 | #include <asm/mpspec.h> | 9 | #include <asm/mpspec.h> |
10 | #include <asm/pci_x86.h> | 10 | #include <asm/pci_x86.h> |
11 | 11 | #include <asm/numaq.h> | |
12 | #define XQUAD_PORTIO_BASE 0xfe400000 | ||
13 | #define XQUAD_PORTIO_QUAD 0x40000 /* 256k per quad. */ | ||
14 | 12 | ||
15 | #define BUS2QUAD(global) (mp_bus_id_to_node[global]) | 13 | #define BUS2QUAD(global) (mp_bus_id_to_node[global]) |
16 | 14 | ||
@@ -18,8 +16,6 @@ | |||
18 | 16 | ||
19 | #define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local]) | 17 | #define QUADLOCAL2BUS(quad,local) (quad_local_to_mp_bus_id[quad][local]) |
20 | 18 | ||
21 | #define XQUAD_PORT_ADDR(port, quad) (xquad_portio + (XQUAD_PORTIO_QUAD*quad) + port) | ||
22 | |||
23 | #define PCI_CONF1_MQ_ADDRESS(bus, devfn, reg) \ | 19 | #define PCI_CONF1_MQ_ADDRESS(bus, devfn, reg) \ |
24 | (0x80000000 | (BUS2LOCAL(bus) << 16) | (devfn << 8) | (reg & ~3)) | 20 | (0x80000000 | (BUS2LOCAL(bus) << 16) | (devfn << 8) | (reg & ~3)) |
25 | 21 | ||
@@ -152,14 +148,8 @@ int __init pci_numaq_init(void) | |||
152 | { | 148 | { |
153 | int quad; | 149 | int quad; |
154 | 150 | ||
155 | if (!found_numaq) | ||
156 | return 0; | ||
157 | |||
158 | raw_pci_ops = &pci_direct_conf1_mq; | 151 | raw_pci_ops = &pci_direct_conf1_mq; |
159 | 152 | ||
160 | if (pcibios_scanned++) | ||
161 | return 0; | ||
162 | |||
163 | pci_root_bus = pcibios_scan_root(0); | 153 | pci_root_bus = pcibios_scan_root(0); |
164 | if (pci_root_bus) | 154 | if (pci_root_bus) |
165 | pci_bus_add_devices(pci_root_bus); | 155 | pci_bus_add_devices(pci_root_bus); |
diff --git a/arch/x86/pci/olpc.c b/arch/x86/pci/olpc.c index b889d824f7c6..b34815408f58 100644 --- a/arch/x86/pci/olpc.c +++ b/arch/x86/pci/olpc.c | |||
@@ -304,9 +304,6 @@ static struct pci_raw_ops pci_olpc_conf = { | |||
304 | 304 | ||
305 | int __init pci_olpc_init(void) | 305 | int __init pci_olpc_init(void) |
306 | { | 306 | { |
307 | if (!machine_is_olpc() || olpc_has_vsa()) | ||
308 | return -ENODEV; | ||
309 | |||
310 | printk(KERN_INFO "PCI: Using configuration type OLPC\n"); | 307 | printk(KERN_INFO "PCI: Using configuration type OLPC\n"); |
311 | raw_pci_ops = &pci_olpc_conf; | 308 | raw_pci_ops = &pci_olpc_conf; |
312 | is_lx = is_geode_lx(); | 309 | is_lx = is_geode_lx(); |
diff --git a/arch/x86/pci/pcbios.c b/arch/x86/pci/pcbios.c index 1c975cc9839e..59a225c17b84 100644 --- a/arch/x86/pci/pcbios.c +++ b/arch/x86/pci/pcbios.c | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | #include <linux/pci.h> | 5 | #include <linux/pci.h> |
6 | #include <linux/init.h> | 6 | #include <linux/init.h> |
7 | #include <linux/slab.h> | ||
7 | #include <linux/module.h> | 8 | #include <linux/module.h> |
8 | #include <linux/uaccess.h> | 9 | #include <linux/uaccess.h> |
9 | #include <asm/pci_x86.h> | 10 | #include <asm/pci_x86.h> |
diff --git a/arch/x86/pci/visws.c b/arch/x86/pci/visws.c index bcead7a46871..03008f72eb04 100644 --- a/arch/x86/pci/visws.c +++ b/arch/x86/pci/visws.c | |||
@@ -69,9 +69,6 @@ void __init pcibios_update_irq(struct pci_dev *dev, int irq) | |||
69 | 69 | ||
70 | int __init pci_visws_init(void) | 70 | int __init pci_visws_init(void) |
71 | { | 71 | { |
72 | if (!is_visws_box()) | ||
73 | return -1; | ||
74 | |||
75 | pcibios_enable_irq = &pci_visws_enable_irq; | 72 | pcibios_enable_irq = &pci_visws_enable_irq; |
76 | pcibios_disable_irq = &pci_visws_disable_irq; | 73 | pcibios_disable_irq = &pci_visws_disable_irq; |
77 | 74 | ||
@@ -90,5 +87,6 @@ int __init pci_visws_init(void) | |||
90 | pci_scan_bus_with_sysdata(pci_bus1); | 87 | pci_scan_bus_with_sysdata(pci_bus1); |
91 | pci_fixup_irqs(pci_common_swizzle, visws_map_irq); | 88 | pci_fixup_irqs(pci_common_swizzle, visws_map_irq); |
92 | pcibios_resource_survey(); | 89 | pcibios_resource_survey(); |
93 | return 0; | 90 | /* Request bus scan */ |
91 | return 1; | ||
94 | } | 92 | } |