aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiang Liu <jiang.liu@linux.intel.com>2015-10-14 02:29:37 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-10-16 16:18:51 -0400
commit3772aea7d6f36cfa1dae17f04ffed64b4d747aab (patch)
tree36281764be48798d60d2193ac94ac0e13d4e4334
parent91236ecc74a25431138f71b6d52e130cd0f774b3 (diff)
ia64/PCI/ACPI: Use common ACPI resource parsing interface for host bridge
Use common ACPI resource parsing interface to parse ACPI resources for PCI host bridge, so we could share more code between IA64 and x86. Later we will consolidate arch specific implementations into ACPI core. Tested-by: Tony Luck <tony.luck@intel.com> Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com> Reviewed-by: Hanjun Guo <hanjun.guo@linaro.org> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--arch/ia64/pci/pci.c414
1 files changed, 193 insertions, 221 deletions
diff --git a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
index 7cc3be9fa7c6..d20db9e48014 100644
--- a/arch/ia64/pci/pci.c
+++ b/arch/ia64/pci/pci.c
@@ -115,29 +115,12 @@ struct pci_ops pci_root_ops = {
115 .write = pci_write, 115 .write = pci_write,
116}; 116};
117 117
118/* Called by ACPI when it finds a new root bus. */
119
120static struct pci_controller *alloc_pci_controller(int seg)
121{
122 struct pci_controller *controller;
123
124 controller = kzalloc(sizeof(*controller), GFP_KERNEL);
125 if (!controller)
126 return NULL;
127
128 controller->segment = seg;
129 return controller;
130}
131
132struct pci_root_info { 118struct pci_root_info {
119 struct pci_controller controller;
133 struct acpi_device *bridge; 120 struct acpi_device *bridge;
134 struct pci_controller *controller;
135 struct list_head resources; 121 struct list_head resources;
136 struct resource *res;
137 resource_size_t *res_offset;
138 unsigned int res_num;
139 struct list_head io_resources; 122 struct list_head io_resources;
140 char *name; 123 char name[16];
141}; 124};
142 125
143static unsigned int 126static unsigned int
@@ -168,11 +151,11 @@ new_space (u64 phys_base, int sparse)
168 return i; 151 return i;
169} 152}
170 153
171static u64 add_io_space(struct pci_root_info *info, 154static int add_io_space(struct device *dev, struct pci_root_info *info,
172 struct acpi_resource_address64 *addr) 155 struct resource_entry *entry)
173{ 156{
174 struct iospace_resource *iospace; 157 struct iospace_resource *iospace;
175 struct resource *resource; 158 struct resource *resource, *res = entry->res;
176 char *name; 159 char *name;
177 unsigned long base, min, max, base_port; 160 unsigned long base, min, max, base_port;
178 unsigned int sparse = 0, space_nr, len; 161 unsigned int sparse = 0, space_nr, len;
@@ -180,27 +163,24 @@ static u64 add_io_space(struct pci_root_info *info,
180 len = strlen(info->name) + 32; 163 len = strlen(info->name) + 32;
181 iospace = kzalloc(sizeof(*iospace) + len, GFP_KERNEL); 164 iospace = kzalloc(sizeof(*iospace) + len, GFP_KERNEL);
182 if (!iospace) { 165 if (!iospace) {
183 dev_err(&info->bridge->dev, 166 dev_err(dev, "PCI: No memory for %s I/O port space\n",
184 "PCI: No memory for %s I/O port space\n", 167 info->name);
185 info->name); 168 return -ENOMEM;
186 goto out;
187 } 169 }
188 170
189 name = (char *)(iospace + 1); 171 if (res->flags & IORESOURCE_IO_SPARSE)
190
191 min = addr->address.minimum;
192 max = min + addr->address.address_length - 1;
193 if (addr->info.io.translation_type == ACPI_SPARSE_TRANSLATION)
194 sparse = 1; 172 sparse = 1;
195 173 space_nr = new_space(entry->offset, sparse);
196 space_nr = new_space(addr->address.translation_offset, sparse);
197 if (space_nr == ~0) 174 if (space_nr == ~0)
198 goto free_resource; 175 goto free_resource;
199 176
177 name = (char *)(iospace + 1);
178 min = res->start - entry->offset;
179 max = res->end - entry->offset;
200 base = __pa(io_space[space_nr].mmio_base); 180 base = __pa(io_space[space_nr].mmio_base);
201 base_port = IO_SPACE_BASE(space_nr); 181 base_port = IO_SPACE_BASE(space_nr);
202 snprintf(name, len, "%s I/O Ports %08lx-%08lx", info->name, 182 snprintf(name, len, "%s I/O Ports %08lx-%08lx", info->name,
203 base_port + min, base_port + max); 183 base_port + min, base_port + max);
204 184
205 /* 185 /*
206 * The SDM guarantees the legacy 0-64K space is sparse, but if the 186 * The SDM guarantees the legacy 0-64K space is sparse, but if the
@@ -216,153 +196,195 @@ static u64 add_io_space(struct pci_root_info *info,
216 resource->start = base + (sparse ? IO_SPACE_SPARSE_ENCODING(min) : min); 196 resource->start = base + (sparse ? IO_SPACE_SPARSE_ENCODING(min) : min);
217 resource->end = base + (sparse ? IO_SPACE_SPARSE_ENCODING(max) : max); 197 resource->end = base + (sparse ? IO_SPACE_SPARSE_ENCODING(max) : max);
218 if (insert_resource(&iomem_resource, resource)) { 198 if (insert_resource(&iomem_resource, resource)) {
219 dev_err(&info->bridge->dev, 199 dev_err(dev,
220 "can't allocate host bridge io space resource %pR\n", 200 "can't allocate host bridge io space resource %pR\n",
221 resource); 201 resource);
222 goto free_resource; 202 goto free_resource;
223 } 203 }
224 204
205 entry->offset = base_port;
206 res->start = min + base_port;
207 res->end = max + base_port;
225 list_add_tail(&iospace->list, &info->io_resources); 208 list_add_tail(&iospace->list, &info->io_resources);
226 return base_port; 209
210 return 0;
227 211
228free_resource: 212free_resource:
229 kfree(iospace); 213 kfree(iospace);
230out: 214 return -ENOSPC;
231 return ~0; 215}
216
217/*
218 * An IO port or MMIO resource assigned to a PCI host bridge may be
219 * consumed by the host bridge itself or available to its child
220 * bus/devices. The ACPI specification defines a bit (Producer/Consumer)
221 * to tell whether the resource is consumed by the host bridge itself,
222 * but firmware hasn't used that bit consistently, so we can't rely on it.
223 *
224 * On x86 and IA64 platforms, all IO port and MMIO resources are assumed
225 * to be available to child bus/devices except one special case:
226 * IO port [0xCF8-0xCFF] is consumed by the host bridge itself
227 * to access PCI configuration space.
228 *
229 * So explicitly filter out PCI CFG IO ports[0xCF8-0xCFF].
230 */
231static bool resource_is_pcicfg_ioport(struct resource *res)
232{
233 return (res->flags & IORESOURCE_IO) &&
234 res->start == 0xCF8 && res->end == 0xCFF;
232} 235}
233 236
234static acpi_status resource_to_window(struct acpi_resource *resource, 237static int
235 struct acpi_resource_address64 *addr) 238probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,
239 int busnum, int domain)
236{ 240{
237 acpi_status status; 241 int ret;
242 struct list_head *list = &info->resources;
243 struct resource_entry *entry, *tmp;
238 244
239 /* 245 ret = acpi_dev_get_resources(device, list,
240 * We're only interested in _CRS descriptors that are 246 acpi_dev_filter_resource_type_cb,
241 * - address space descriptors for memory or I/O space 247 (void *)(IORESOURCE_IO | IORESOURCE_MEM));
242 * - non-zero size 248 if (ret < 0)
243 */ 249 dev_warn(&device->dev,
244 status = acpi_resource_to_address64(resource, addr); 250 "failed to parse _CRS method, error code %d\n", ret);
245 if (ACPI_SUCCESS(status) && 251 else if (ret == 0)
246 (addr->resource_type == ACPI_MEMORY_RANGE || 252 dev_dbg(&device->dev,
247 addr->resource_type == ACPI_IO_RANGE) && 253 "no IO and memory resources present in _CRS\n");
248 addr->address.address_length) 254 else
249 return AE_OK; 255 resource_list_for_each_entry_safe(entry, tmp, list) {
250 256 if ((entry->res->flags & IORESOURCE_DISABLED) ||
251 return AE_ERROR; 257 resource_is_pcicfg_ioport(entry->res))
252} 258 resource_list_destroy_entry(entry);
253 259 else
254static acpi_status count_window(struct acpi_resource *resource, void *data) 260 entry->res->name = info->name;
255{ 261 }
256 unsigned int *windows = (unsigned int *) data;
257 struct acpi_resource_address64 addr;
258 acpi_status status;
259
260 status = resource_to_window(resource, &addr);
261 if (ACPI_SUCCESS(status))
262 (*windows)++;
263
264 return AE_OK;
265}
266
267static acpi_status add_window(struct acpi_resource *res, void *data)
268{
269 struct pci_root_info *info = data;
270 struct resource *resource;
271 struct acpi_resource_address64 addr;
272 acpi_status status;
273 unsigned long flags, offset = 0;
274 struct resource *root;
275
276 /* Return AE_OK for non-window resources to keep scanning for more */
277 status = resource_to_window(res, &addr);
278 if (!ACPI_SUCCESS(status))
279 return AE_OK;
280
281 if (addr.resource_type == ACPI_MEMORY_RANGE) {
282 flags = IORESOURCE_MEM;
283 root = &iomem_resource;
284 offset = addr.address.translation_offset;
285 } else if (addr.resource_type == ACPI_IO_RANGE) {
286 flags = IORESOURCE_IO;
287 root = &ioport_resource;
288 offset = add_io_space(info, &addr);
289 if (offset == ~0)
290 return AE_OK;
291 } else
292 return AE_OK;
293
294 resource = &info->res[info->res_num];
295 resource->name = info->name;
296 resource->flags = flags;
297 resource->start = addr.address.minimum + offset;
298 resource->end = resource->start + addr.address.address_length - 1;
299 info->res_offset[info->res_num] = offset;
300
301 if (insert_resource(root, resource)) {
302 dev_err(&info->bridge->dev,
303 "can't allocate host bridge window %pR\n",
304 resource);
305 } else {
306 if (offset)
307 dev_info(&info->bridge->dev, "host bridge window %pR "
308 "(PCI address [%#llx-%#llx])\n",
309 resource,
310 resource->start - offset,
311 resource->end - offset);
312 else
313 dev_info(&info->bridge->dev,
314 "host bridge window %pR\n", resource);
315 }
316 /* HP's firmware has a hack to work around a Windows bug.
317 * Ignore these tiny memory ranges */
318 if (!((resource->flags & IORESOURCE_MEM) &&
319 (resource->end - resource->start < 16)))
320 pci_add_resource_offset(&info->resources, resource,
321 info->res_offset[info->res_num]);
322 262
323 info->res_num++; 263 return ret;
324 return AE_OK;
325} 264}
326 265
327static void free_pci_root_info_res(struct pci_root_info *info) 266static void validate_resources(struct device *dev, struct list_head *resources,
328{ 267 unsigned long type)
329 struct iospace_resource *iospace, *tmp; 268{
269 LIST_HEAD(list);
270 struct resource *res1, *res2, *root = NULL;
271 struct resource_entry *tmp, *entry, *entry2;
272
273 BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0);
274 root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource;
275
276 list_splice_init(resources, &list);
277 resource_list_for_each_entry_safe(entry, tmp, &list) {
278 bool free = false;
279 resource_size_t end;
280
281 res1 = entry->res;
282 if (!(res1->flags & type))
283 goto next;
284
285 /* Exclude non-addressable range or non-addressable portion */
286 end = min(res1->end, root->end);
287 if (end <= res1->start) {
288 dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n",
289 res1);
290 free = true;
291 goto next;
292 } else if (res1->end != end) {
293 dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n",
294 res1, (unsigned long long)end + 1,
295 (unsigned long long)res1->end);
296 res1->end = end;
297 }
330 298
331 list_for_each_entry_safe(iospace, tmp, &info->io_resources, list) 299 resource_list_for_each_entry(entry2, resources) {
332 kfree(iospace); 300 res2 = entry2->res;
301 if (!(res2->flags & type))
302 continue;
303
304 /*
305 * I don't like throwing away windows because then
306 * our resources no longer match the ACPI _CRS, but
307 * the kernel resource tree doesn't allow overlaps.
308 */
309 if (resource_overlaps(res1, res2)) {
310 res2->start = min(res1->start, res2->start);
311 res2->end = max(res1->end, res2->end);
312 dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n",
313 res2, res1);
314 free = true;
315 goto next;
316 }
317 }
333 318
334 kfree(info->name); 319next:
335 kfree(info->res); 320 resource_list_del(entry);
336 info->res = NULL; 321 if (free)
337 kfree(info->res_offset); 322 resource_list_free_entry(entry);
338 info->res_offset = NULL; 323 else
339 info->res_num = 0; 324 resource_list_add_tail(entry, resources);
340 kfree(info->controller); 325 }
341 info->controller = NULL; 326}
327
328static void add_resources(struct pci_root_info *info, struct device *dev)
329{
330 struct resource_entry *entry, *tmp;
331 struct resource *res, *conflict, *root = NULL;
332 struct list_head *list = &info->resources;
333
334 validate_resources(dev, list, IORESOURCE_MEM);
335 validate_resources(dev, list, IORESOURCE_IO);
336
337 resource_list_for_each_entry_safe(entry, tmp, list) {
338 res = entry->res;
339 if (res->flags & IORESOURCE_MEM) {
340 root = &iomem_resource;
341 /*
342 * HP's firmware has a hack to work around a Windows
343 * bug. Ignore these tiny memory ranges.
344 */
345 if (resource_size(res) <= 16) {
346 resource_list_destroy_entry(entry);
347 continue;
348 }
349 } else if (res->flags & IORESOURCE_IO) {
350 root = &ioport_resource;
351 if (add_io_space(&info->bridge->dev, info, entry)) {
352 resource_list_destroy_entry(entry);
353 continue;
354 }
355 } else {
356 BUG_ON(res);
357 }
358
359 conflict = insert_resource_conflict(root, res);
360 if (conflict) {
361 dev_info(dev,
362 "ignoring host bridge window %pR (conflicts with %s %pR)\n",
363 res, conflict->name, conflict);
364 resource_list_destroy_entry(entry);
365 }
366 }
342} 367}
343 368
344static void __release_pci_root_info(struct pci_root_info *info) 369static void __release_pci_root_info(struct pci_root_info *info)
345{ 370{
346 int i;
347 struct resource *res; 371 struct resource *res;
348 struct iospace_resource *iospace; 372 struct iospace_resource *iospace, *tmp;
373 struct resource_entry *entry, *tentry;
349 374
350 list_for_each_entry(iospace, &info->io_resources, list) 375 list_for_each_entry_safe(iospace, tmp, &info->io_resources, list) {
351 release_resource(&iospace->res); 376 release_resource(&iospace->res);
377 kfree(iospace);
378 }
352 379
353 for (i = 0; i < info->res_num; i++) { 380 resource_list_for_each_entry_safe(entry, tentry, &info->resources) {
354 res = &info->res[i]; 381 res = entry->res;
355 382 if (res->parent &&
356 if (!res->parent) 383 (res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
357 continue; 384 release_resource(res);
358 385 resource_list_destroy_entry(entry);
359 if (!(res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
360 continue;
361
362 release_resource(res);
363 } 386 }
364 387
365 free_pci_root_info_res(info);
366 kfree(info); 388 kfree(info);
367} 389}
368 390
@@ -373,99 +395,49 @@ static void release_pci_root_info(struct pci_host_bridge *bridge)
373 __release_pci_root_info(info); 395 __release_pci_root_info(info);
374} 396}
375 397
376static int
377probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,
378 int busnum, int domain)
379{
380 char *name;
381
382 name = kmalloc(16, GFP_KERNEL);
383 if (!name)
384 return -ENOMEM;
385
386 sprintf(name, "PCI Bus %04x:%02x", domain, busnum);
387 info->bridge = device;
388 info->name = name;
389
390 acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_window,
391 &info->res_num);
392 if (info->res_num) {
393 info->res =
394 kzalloc_node(sizeof(*info->res) * info->res_num,
395 GFP_KERNEL, info->controller->node);
396 if (!info->res) {
397 kfree(name);
398 return -ENOMEM;
399 }
400
401 info->res_offset =
402 kzalloc_node(sizeof(*info->res_offset) * info->res_num,
403 GFP_KERNEL, info->controller->node);
404 if (!info->res_offset) {
405 kfree(name);
406 kfree(info->res);
407 info->res = NULL;
408 return -ENOMEM;
409 }
410
411 info->res_num = 0;
412 acpi_walk_resources(device->handle, METHOD_NAME__CRS,
413 add_window, info);
414 } else
415 kfree(name);
416
417 return 0;
418}
419
420struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root) 398struct pci_bus *pci_acpi_scan_root(struct acpi_pci_root *root)
421{ 399{
422 struct acpi_device *device = root->device; 400 struct acpi_device *device = root->device;
423 int domain = root->segment; 401 int domain = root->segment;
424 int bus = root->secondary.start; 402 int bus = root->secondary.start;
425 struct pci_controller *controller; 403 struct pci_root_info *info;
426 struct pci_root_info *info = NULL;
427 int busnum = root->secondary.start;
428 struct pci_bus *pbus; 404 struct pci_bus *pbus;
429 int ret; 405 int ret;
430 406
431 controller = alloc_pci_controller(domain);
432 if (!controller)
433 return NULL;
434
435 controller->companion = device;
436 controller->node = acpi_get_node(device->handle);
437
438 info = kzalloc(sizeof(*info), GFP_KERNEL); 407 info = kzalloc(sizeof(*info), GFP_KERNEL);
439 if (!info) { 408 if (!info) {
440 dev_err(&device->dev, 409 dev_err(&device->dev,
441 "pci_bus %04x:%02x: ignored (out of memory)\n", 410 "pci_bus %04x:%02x: ignored (out of memory)\n",
442 domain, busnum); 411 domain, bus);
443 kfree(controller);
444 return NULL; 412 return NULL;
445 } 413 }
446 414
447 info->controller = controller; 415 info->controller.segment = domain;
448 INIT_LIST_HEAD(&info->io_resources); 416 info->controller.companion = device;
417 info->controller.node = acpi_get_node(device->handle);
418 info->bridge = device;
449 INIT_LIST_HEAD(&info->resources); 419 INIT_LIST_HEAD(&info->resources);
420 INIT_LIST_HEAD(&info->io_resources);
421 snprintf(info->name, sizeof(info->name),
422 "PCI Bus %04x:%02x", domain, bus);
450 423
451 ret = probe_pci_root_info(info, device, busnum, domain); 424 ret = probe_pci_root_info(info, device, bus, domain);
452 if (ret) { 425 if (ret <= 0) {
453 kfree(info->controller);
454 kfree(info); 426 kfree(info);
455 return NULL; 427 return NULL;
456 } 428 }
457 /* insert busn resource at first */ 429 add_resources(info, &info->bridge->dev);
458 pci_add_resource(&info->resources, &root->secondary); 430 pci_add_resource(&info->resources, &root->secondary);
431
459 /* 432 /*
460 * See arch/x86/pci/acpi.c. 433 * See arch/x86/pci/acpi.c.
461 * The desired pci bus might already be scanned in a quirk. We 434 * The desired pci bus might already be scanned in a quirk. We
462 * should handle the case here, but it appears that IA64 hasn't 435 * should handle the case here, but it appears that IA64 hasn't
463 * such quirk. So we just ignore the case now. 436 * such quirk. So we just ignore the case now.
464 */ 437 */
465 pbus = pci_create_root_bus(NULL, bus, &pci_root_ops, controller, 438 pbus = pci_create_root_bus(NULL, bus, &pci_root_ops,
466 &info->resources); 439 &info->controller, &info->resources);
467 if (!pbus) { 440 if (!pbus) {
468 pci_free_resource_list(&info->resources);
469 __release_pci_root_info(info); 441 __release_pci_root_info(info);
470 return NULL; 442 return NULL;
471 } 443 }