aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYinghai Lu <yinghai@kernel.org>2017-04-21 01:04:48 -0400
committerBjorn Helgaas <helgaas@kernel.org>2018-02-15 16:07:30 -0500
commitb4a304489ef95b6b921d1faa46438d9ea89cfd4b (patch)
treef6105882b0c7a6404faa37eea5c82fa90f0a030f
parent7928b2cbe55b2a410a0f5c1f154610059c57b1b2 (diff)
sparc/PCI: Support arbitrary host bridge address offset
Add support for arbitrary bus address offset. Previously we ignored the child (PCI) address in the "ranges" property and assumed it was always zero. That means every host bridge window mapped to PCI bus address zero, e.g., pci_bus 0000:00: root bus resource [mem 0x2000000000000-0x200007fffffff] (bus address [0x00000000-0x7fffffff]) But some systems have host bridge windows with non-zero child addresses, so parse the child address and compute the offset between the parent (CPU) and child (PCI) addresses. This allows windows like these: /pci@305: PCI MEM [mem 0x2000000100000-0x200007effffff] offset 2000000000000 pci_sun4v f02ae7f8: PCI host bridge to bus 0000:00 pci_bus 0000:00: root bus resource [mem 0x2000000100000-0x200007effffff] (bus address [0x00100000-0x7effffff]) [bhelgaas: changelog] Tested-by: Khalid Aziz <khalid.aziz@oracle.com> Signed-off-by: Yinghai Lu <yinghai@kernel.org> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Acked-by: David S. Miller <davem@davemloft.net> Cc: sparclinux@vger.kernel.org
-rw-r--r--arch/sparc/kernel/pci.c6
-rw-r--r--arch/sparc/kernel/pci_common.c34
-rw-r--r--arch/sparc/kernel/pci_impl.h4
3 files changed, 33 insertions, 11 deletions
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c
index 220d0f36560a..41b20edb427d 100644
--- a/arch/sparc/kernel/pci.c
+++ b/arch/sparc/kernel/pci.c
@@ -664,12 +664,12 @@ struct pci_bus *pci_scan_one_pbm(struct pci_pbm_info *pbm,
664 printk("PCI: Scanning PBM %s\n", node->full_name); 664 printk("PCI: Scanning PBM %s\n", node->full_name);
665 665
666 pci_add_resource_offset(&resources, &pbm->io_space, 666 pci_add_resource_offset(&resources, &pbm->io_space,
667 pbm->io_space.start); 667 pbm->io_offset);
668 pci_add_resource_offset(&resources, &pbm->mem_space, 668 pci_add_resource_offset(&resources, &pbm->mem_space,
669 pbm->mem_space.start); 669 pbm->mem_offset);
670 if (pbm->mem64_space.flags) 670 if (pbm->mem64_space.flags)
671 pci_add_resource_offset(&resources, &pbm->mem64_space, 671 pci_add_resource_offset(&resources, &pbm->mem64_space,
672 pbm->mem_space.start); 672 pbm->mem64_offset);
673 pbm->busn.start = pbm->pci_first_busno; 673 pbm->busn.start = pbm->pci_first_busno;
674 pbm->busn.end = pbm->pci_last_busno; 674 pbm->busn.end = pbm->pci_last_busno;
675 pbm->busn.flags = IORESOURCE_BUS; 675 pbm->busn.flags = IORESOURCE_BUS;
diff --git a/arch/sparc/kernel/pci_common.c b/arch/sparc/kernel/pci_common.c
index 1e10fb26fa88..14fa74f90fdb 100644
--- a/arch/sparc/kernel/pci_common.c
+++ b/arch/sparc/kernel/pci_common.c
@@ -397,6 +397,8 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
397 int i, saw_mem, saw_io; 397 int i, saw_mem, saw_io;
398 int num_pbm_ranges; 398 int num_pbm_ranges;
399 399
400 /* Corresponding generic code in of_pci_get_host_bridge_resources() */
401
400 saw_mem = saw_io = 0; 402 saw_mem = saw_io = 0;
401 pbm_ranges = of_get_property(pbm->op->dev.of_node, "ranges", &i); 403 pbm_ranges = of_get_property(pbm->op->dev.of_node, "ranges", &i);
402 if (!pbm_ranges) { 404 if (!pbm_ranges) {
@@ -411,13 +413,16 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
411 413
412 for (i = 0; i < num_pbm_ranges; i++) { 414 for (i = 0; i < num_pbm_ranges; i++) {
413 const struct linux_prom_pci_ranges *pr = &pbm_ranges[i]; 415 const struct linux_prom_pci_ranges *pr = &pbm_ranges[i];
414 unsigned long a, size; 416 unsigned long a, size, region_a;
415 u32 parent_phys_hi, parent_phys_lo; 417 u32 parent_phys_hi, parent_phys_lo;
418 u32 child_phys_mid, child_phys_lo;
416 u32 size_hi, size_lo; 419 u32 size_hi, size_lo;
417 int type; 420 int type;
418 421
419 parent_phys_hi = pr->parent_phys_hi; 422 parent_phys_hi = pr->parent_phys_hi;
420 parent_phys_lo = pr->parent_phys_lo; 423 parent_phys_lo = pr->parent_phys_lo;
424 child_phys_mid = pr->child_phys_mid;
425 child_phys_lo = pr->child_phys_lo;
421 if (tlb_type == hypervisor) 426 if (tlb_type == hypervisor)
422 parent_phys_hi &= 0x0fffffff; 427 parent_phys_hi &= 0x0fffffff;
423 428
@@ -427,6 +432,8 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
427 type = (pr->child_phys_hi >> 24) & 0x3; 432 type = (pr->child_phys_hi >> 24) & 0x3;
428 a = (((unsigned long)parent_phys_hi << 32UL) | 433 a = (((unsigned long)parent_phys_hi << 32UL) |
429 ((unsigned long)parent_phys_lo << 0UL)); 434 ((unsigned long)parent_phys_lo << 0UL));
435 region_a = (((unsigned long)child_phys_mid << 32UL) |
436 ((unsigned long)child_phys_lo << 0UL));
430 size = (((unsigned long)size_hi << 32UL) | 437 size = (((unsigned long)size_hi << 32UL) |
431 ((unsigned long)size_lo << 0UL)); 438 ((unsigned long)size_lo << 0UL));
432 439
@@ -441,6 +448,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
441 pbm->io_space.start = a; 448 pbm->io_space.start = a;
442 pbm->io_space.end = a + size - 1UL; 449 pbm->io_space.end = a + size - 1UL;
443 pbm->io_space.flags = IORESOURCE_IO; 450 pbm->io_space.flags = IORESOURCE_IO;
451 pbm->io_offset = a - region_a;
444 saw_io = 1; 452 saw_io = 1;
445 break; 453 break;
446 454
@@ -449,6 +457,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
449 pbm->mem_space.start = a; 457 pbm->mem_space.start = a;
450 pbm->mem_space.end = a + size - 1UL; 458 pbm->mem_space.end = a + size - 1UL;
451 pbm->mem_space.flags = IORESOURCE_MEM; 459 pbm->mem_space.flags = IORESOURCE_MEM;
460 pbm->mem_offset = a - region_a;
452 saw_mem = 1; 461 saw_mem = 1;
453 break; 462 break;
454 463
@@ -457,6 +466,7 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
457 pbm->mem64_space.start = a; 466 pbm->mem64_space.start = a;
458 pbm->mem64_space.end = a + size - 1UL; 467 pbm->mem64_space.end = a + size - 1UL;
459 pbm->mem64_space.flags = IORESOURCE_MEM; 468 pbm->mem64_space.flags = IORESOURCE_MEM;
469 pbm->mem64_offset = a - region_a;
460 saw_mem = 1; 470 saw_mem = 1;
461 break; 471 break;
462 472
@@ -472,14 +482,22 @@ void pci_determine_mem_io_space(struct pci_pbm_info *pbm)
472 prom_halt(); 482 prom_halt();
473 } 483 }
474 484
475 printk("%s: PCI IO[%llx] MEM[%llx]", 485 if (pbm->io_space.flags)
476 pbm->name, 486 printk("%s: PCI IO %pR offset %llx\n",
477 pbm->io_space.start, 487 pbm->name, &pbm->io_space, pbm->io_offset);
478 pbm->mem_space.start); 488 if (pbm->mem_space.flags)
489 printk("%s: PCI MEM %pR offset %llx\n",
490 pbm->name, &pbm->mem_space, pbm->mem_offset);
491 if (pbm->mem64_space.flags && pbm->mem_space.flags) {
492 if (pbm->mem64_space.start <= pbm->mem_space.end)
493 pbm->mem64_space.start = pbm->mem_space.end + 1;
494 if (pbm->mem64_space.start > pbm->mem64_space.end)
495 pbm->mem64_space.flags = 0;
496 }
497
479 if (pbm->mem64_space.flags) 498 if (pbm->mem64_space.flags)
480 printk(" MEM64[%llx]", 499 printk("%s: PCI MEM64 %pR offset %llx\n",
481 pbm->mem64_space.start); 500 pbm->name, &pbm->mem64_space, pbm->mem64_offset);
482 printk("\n");
483 501
484 pbm->io_space.name = pbm->mem_space.name = pbm->name; 502 pbm->io_space.name = pbm->mem_space.name = pbm->name;
485 pbm->mem64_space.name = pbm->name; 503 pbm->mem64_space.name = pbm->name;
diff --git a/arch/sparc/kernel/pci_impl.h b/arch/sparc/kernel/pci_impl.h
index ac172961d276..4e3d15189fa9 100644
--- a/arch/sparc/kernel/pci_impl.h
+++ b/arch/sparc/kernel/pci_impl.h
@@ -100,6 +100,10 @@ struct pci_pbm_info {
100 struct resource mem_space; 100 struct resource mem_space;
101 struct resource mem64_space; 101 struct resource mem64_space;
102 struct resource busn; 102 struct resource busn;
103 /* offset */
104 resource_size_t io_offset;
105 resource_size_t mem_offset;
106 resource_size_t mem64_offset;
103 107
104 /* Base of PCI Config space, can be per-PBM or shared. */ 108 /* Base of PCI Config space, can be per-PBM or shared. */
105 unsigned long config_space; 109 unsigned long config_space;