aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/pci/acpi.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/pci/acpi.c')
-rw-r--r--arch/x86/pci/acpi.c81
1 files changed, 45 insertions, 36 deletions
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 6e22454bfaa..31930fd30ea 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -3,6 +3,7 @@
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
@@ -65,14 +66,44 @@ resource_to_addr(struct acpi_resource *resource,
65 struct acpi_resource_address64 *addr) 66 struct acpi_resource_address64 *addr)
66{ 67{
67 acpi_status status; 68 acpi_status status;
68 69 struct acpi_resource_memory24 *memory24;
69 status = acpi_resource_to_address64(resource, addr); 70 struct acpi_resource_memory32 *memory32;
70 if (ACPI_SUCCESS(status) && 71 struct acpi_resource_fixed_memory32 *fixed_memory32;
71 (addr->resource_type == ACPI_MEMORY_RANGE || 72
72 addr->resource_type == ACPI_IO_RANGE) && 73 memset(addr, 0, sizeof(*addr));
73 addr->address_length > 0 && 74 switch (resource->type) {
74 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;
75 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;
76 } 107 }
77 return AE_ERROR; 108 return AE_ERROR;
78} 109}
@@ -90,30 +121,6 @@ count_resource(struct acpi_resource *acpi_res, void *data)
90 return AE_OK; 121 return AE_OK;
91} 122}
92 123
93static void
94align_resource(struct acpi_device *bridge, struct resource *res)
95{
96 int align = (res->flags & IORESOURCE_MEM) ? 16 : 4;
97
98 /*
99 * Host bridge windows are not BARs, but the decoders on the PCI side
100 * that claim this address space have starting alignment and length
101 * constraints, so fix any obvious BIOS goofs.
102 */
103 if (!IS_ALIGNED(res->start, align)) {
104 dev_printk(KERN_DEBUG, &bridge->dev,
105 "host bridge window %pR invalid; "
106 "aligning start to %d-byte boundary\n", res, align);
107 res->start &= ~(align - 1);
108 }
109 if (!IS_ALIGNED(res->end + 1, align)) {
110 dev_printk(KERN_DEBUG, &bridge->dev,
111 "host bridge window %pR invalid; "
112 "aligning end to %d-byte boundary\n", res, align);
113 res->end = ALIGN(res->end, align) - 1;
114 }
115}
116
117static acpi_status 124static acpi_status
118setup_resource(struct acpi_resource *acpi_res, void *data) 125setup_resource(struct acpi_resource *acpi_res, void *data)
119{ 126{
@@ -122,7 +129,7 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
122 struct acpi_resource_address64 addr; 129 struct acpi_resource_address64 addr;
123 acpi_status status; 130 acpi_status status;
124 unsigned long flags; 131 unsigned long flags;
125 struct resource *root; 132 struct resource *root, *conflict;
126 u64 start, end; 133 u64 start, end;
127 134
128 status = resource_to_addr(acpi_res, &addr); 135 status = resource_to_addr(acpi_res, &addr);
@@ -141,7 +148,7 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
141 return AE_OK; 148 return AE_OK;
142 149
143 start = addr.minimum + addr.translation_offset; 150 start = addr.minimum + addr.translation_offset;
144 end = start + addr.address_length - 1; 151 end = addr.maximum + addr.translation_offset;
145 152
146 res = &info->res[info->res_num]; 153 res = &info->res[info->res_num];
147 res->name = info->name; 154 res->name = info->name;
@@ -149,7 +156,6 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
149 res->start = start; 156 res->start = start;
150 res->end = end; 157 res->end = end;
151 res->child = NULL; 158 res->child = NULL;
152 align_resource(info->bridge, res);
153 159
154 if (!pci_use_crs) { 160 if (!pci_use_crs) {
155 dev_printk(KERN_DEBUG, &info->bridge->dev, 161 dev_printk(KERN_DEBUG, &info->bridge->dev,
@@ -157,9 +163,12 @@ setup_resource(struct acpi_resource *acpi_res, void *data)
157 return AE_OK; 163 return AE_OK;
158 } 164 }
159 165
160 if (insert_resource(root, res)) { 166 conflict = insert_resource_conflict(root, res);
167 if (conflict) {
161 dev_err(&info->bridge->dev, 168 dev_err(&info->bridge->dev,
162 "can't allocate host bridge window %pR\n", res); 169 "address space collision: host bridge window %pR "
170 "conflicts with %s %pR\n",
171 res, conflict->name, conflict);
163 } else { 172 } else {
164 pci_bus_add_resource(info->bus, res, 0); 173 pci_bus_add_resource(info->bus, res, 0);
165 info->res_num++; 174 info->res_num++;