aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/kernel-parameters.txt2
-rw-r--r--arch/x86/pci/acpi.c139
-rw-r--r--arch/x86/pci/common.c3
-rw-r--r--arch/x86/pci/pci.h1
4 files changed, 145 insertions, 0 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 3f0173f45019..e9acd5540d29 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1318,6 +1318,8 @@ and is between 256 and 4096 characters. It is defined in the file
1318 IRQ routing is enabled. 1318 IRQ routing is enabled.
1319 noacpi [X86-32] Do not use ACPI for IRQ routing 1319 noacpi [X86-32] Do not use ACPI for IRQ routing
1320 or for PCI scanning. 1320 or for PCI scanning.
1321 use_crs [X86-32] Use _CRS for PCI resource
1322 allocation.
1321 routeirq Do IRQ routing for all PCI devices. 1323 routeirq Do IRQ routing for all PCI devices.
1322 This is normally done in pci_enable_device(), 1324 This is normally done in pci_enable_device(),
1323 so this option is a temporary workaround 1325 so this option is a temporary workaround
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c
index 1dd6f3fc077d..c6fd3a6afa42 100644
--- a/arch/x86/pci/acpi.c
+++ b/arch/x86/pci/acpi.c
@@ -45,6 +45,142 @@ static struct dmi_system_id acpi_pciprobe_dmi_table[] = {
45 {} 45 {}
46}; 46};
47 47
48struct pci_root_info {
49 char *name;
50 unsigned int res_num;
51 struct resource *res;
52 struct pci_bus *bus;
53 int busnum;
54};
55
56static acpi_status
57resource_to_addr(struct acpi_resource *resource,
58 struct acpi_resource_address64 *addr)
59{
60 acpi_status status;
61
62 status = acpi_resource_to_address64(resource, addr);
63 if (ACPI_SUCCESS(status) &&
64 (addr->resource_type == ACPI_MEMORY_RANGE ||
65 addr->resource_type == ACPI_IO_RANGE) &&
66 addr->address_length > 0 &&
67 addr->producer_consumer == ACPI_PRODUCER) {
68 return AE_OK;
69 }
70 return AE_ERROR;
71}
72
73static acpi_status
74count_resource(struct acpi_resource *acpi_res, void *data)
75{
76 struct pci_root_info *info = data;
77 struct acpi_resource_address64 addr;
78 acpi_status status;
79
80 status = resource_to_addr(acpi_res, &addr);
81 if (ACPI_SUCCESS(status))
82 info->res_num++;
83 return AE_OK;
84}
85
86static acpi_status
87setup_resource(struct acpi_resource *acpi_res, void *data)
88{
89 struct pci_root_info *info = data;
90 struct resource *res;
91 struct acpi_resource_address64 addr;
92 acpi_status status;
93 unsigned long flags;
94 struct resource *root;
95
96 status = resource_to_addr(acpi_res, &addr);
97 if (!ACPI_SUCCESS(status))
98 return AE_OK;
99
100 if (addr.resource_type == ACPI_MEMORY_RANGE) {
101 root = &iomem_resource;
102 flags = IORESOURCE_MEM;
103 if (addr.info.mem.caching == ACPI_PREFETCHABLE_MEMORY)
104 flags |= IORESOURCE_PREFETCH;
105 } else if (addr.resource_type == ACPI_IO_RANGE) {
106 root = &ioport_resource;
107 flags = IORESOURCE_IO;
108 } else
109 return AE_OK;
110
111 res = &info->res[info->res_num];
112 res->name = info->name;
113 res->flags = flags;
114 res->start = addr.minimum + addr.translation_offset;
115 res->end = res->start + addr.address_length - 1;
116 res->child = NULL;
117
118 if (insert_resource(root, res)) {
119 printk(KERN_ERR "PCI: Failed to allocate 0x%lx-0x%lx "
120 "from %s for %s\n", (unsigned long) res->start,
121 (unsigned long) res->end, root->name, info->name);
122 } else {
123 info->bus->resource[info->res_num] = res;
124 info->res_num++;
125 }
126 return AE_OK;
127}
128
129static void
130adjust_transparent_bridge_resources(struct pci_bus *bus)
131{
132 struct pci_dev *dev;
133
134 list_for_each_entry(dev, &bus->devices, bus_list) {
135 int i;
136 u16 class = dev->class >> 8;
137
138 if (class == PCI_CLASS_BRIDGE_PCI && dev->transparent) {
139 for(i = 3; i < PCI_BUS_NUM_RESOURCES; i++)
140 dev->subordinate->resource[i] =
141 dev->bus->resource[i - 3];
142 }
143 }
144}
145
146static void
147get_current_resources(struct acpi_device *device, int busnum,
148 struct pci_bus *bus)
149{
150 struct pci_root_info info;
151 size_t size;
152
153 info.bus = bus;
154 info.res_num = 0;
155 acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource,
156 &info);
157 if (!info.res_num)
158 return;
159
160 size = sizeof(*info.res) * info.res_num;
161 info.res = kmalloc(size, GFP_KERNEL);
162 if (!info.res)
163 goto res_alloc_fail;
164
165 info.name = kmalloc(12, GFP_KERNEL);
166 if (!info.name)
167 goto name_alloc_fail;
168 sprintf(info.name, "PCI Bus #%02x", busnum);
169
170 info.res_num = 0;
171 acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource,
172 &info);
173 if (info.res_num)
174 adjust_transparent_bridge_resources(bus);
175
176 return;
177
178name_alloc_fail:
179 kfree(info.res);
180res_alloc_fail:
181 return;
182}
183
48struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum) 184struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int domain, int busnum)
49{ 185{
50 struct pci_bus *bus; 186 struct pci_bus *bus;
@@ -89,6 +225,9 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_device *device, int do
89 } 225 }
90 } 226 }
91#endif 227#endif
228
229 if (bus && (pci_probe & PCI_USE__CRS))
230 get_current_resources(device, busnum, bus);
92 231
93 return bus; 232 return bus;
94} 233}
diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 7c4d75e3c5f3..7d6a9a5aa7cd 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -436,6 +436,9 @@ char * __devinit pcibios_setup(char *str)
436 } else if (!strcmp(str, "assign-busses")) { 436 } else if (!strcmp(str, "assign-busses")) {
437 pci_probe |= PCI_ASSIGN_ALL_BUSSES; 437 pci_probe |= PCI_ASSIGN_ALL_BUSSES;
438 return NULL; 438 return NULL;
439 } else if (!strcmp(str, "use_crs")) {
440 pci_probe |= PCI_USE__CRS;
441 return NULL;
439 } else if (!strcmp(str, "routeirq")) { 442 } else if (!strcmp(str, "routeirq")) {
440 pci_routeirq = 1; 443 pci_routeirq = 1;
441 return NULL; 444 return NULL;
diff --git a/arch/x86/pci/pci.h b/arch/x86/pci/pci.h
index 057f335fa3f6..ac56d3916c50 100644
--- a/arch/x86/pci/pci.h
+++ b/arch/x86/pci/pci.h
@@ -27,6 +27,7 @@
27#define PCI_BIOS_IRQ_SCAN 0x2000 27#define PCI_BIOS_IRQ_SCAN 0x2000
28#define PCI_ASSIGN_ALL_BUSSES 0x4000 28#define PCI_ASSIGN_ALL_BUSSES 0x4000
29#define PCI_CAN_SKIP_ISA_ALIGN 0x8000 29#define PCI_CAN_SKIP_ISA_ALIGN 0x8000
30#define PCI_USE__CRS 0x10000
30 31
31extern unsigned int pci_probe; 32extern unsigned int pci_probe;
32extern unsigned long pirq_table_addr; 33extern unsigned long pirq_table_addr;