aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJiang Liu <jiang.liu@linux.intel.com>2015-10-14 02:29:39 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-10-16 16:18:51 -0400
commit2c204383a2922cd6b79b9d78680a049a2144fbcc (patch)
tree390f857746c8ea5e58493629dcbcaa0f3489f8c2
parent3f7abdefc07755d67e2b2b63608d3128f6e0b3c5 (diff)
PCI/ACPI: Add interface acpi_pci_root_create()
Introduce common interface acpi_pci_root_create() and related data structures to create PCI root bus for ACPI PCI host bridges. It will be used to kill duplicated arch specific code for IA64 and x86. It may also help ARM64 in future. Reviewed-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Tested-by: Tony Luck <tony.luck@intel.com> Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com> Acked-by: Bjorn Helgaas <bhelgaas@google.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/acpi/pci_root.c204
-rw-r--r--include/linux/pci-acpi.h24
2 files changed, 228 insertions, 0 deletions
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 393706a5261b..850d7bf0c873 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -652,6 +652,210 @@ static void acpi_pci_root_remove(struct acpi_device *device)
652 kfree(root); 652 kfree(root);
653} 653}
654 654
655/*
656 * Following code to support acpi_pci_root_create() is copied from
657 * arch/x86/pci/acpi.c and modified so it could be reused by x86, IA64
658 * and ARM64.
659 */
660static void acpi_pci_root_validate_resources(struct device *dev,
661 struct list_head *resources,
662 unsigned long type)
663{
664 LIST_HEAD(list);
665 struct resource *res1, *res2, *root = NULL;
666 struct resource_entry *tmp, *entry, *entry2;
667
668 BUG_ON((type & (IORESOURCE_MEM | IORESOURCE_IO)) == 0);
669 root = (type & IORESOURCE_MEM) ? &iomem_resource : &ioport_resource;
670
671 list_splice_init(resources, &list);
672 resource_list_for_each_entry_safe(entry, tmp, &list) {
673 bool free = false;
674 resource_size_t end;
675
676 res1 = entry->res;
677 if (!(res1->flags & type))
678 goto next;
679
680 /* Exclude non-addressable range or non-addressable portion */
681 end = min(res1->end, root->end);
682 if (end <= res1->start) {
683 dev_info(dev, "host bridge window %pR (ignored, not CPU addressable)\n",
684 res1);
685 free = true;
686 goto next;
687 } else if (res1->end != end) {
688 dev_info(dev, "host bridge window %pR ([%#llx-%#llx] ignored, not CPU addressable)\n",
689 res1, (unsigned long long)end + 1,
690 (unsigned long long)res1->end);
691 res1->end = end;
692 }
693
694 resource_list_for_each_entry(entry2, resources) {
695 res2 = entry2->res;
696 if (!(res2->flags & type))
697 continue;
698
699 /*
700 * I don't like throwing away windows because then
701 * our resources no longer match the ACPI _CRS, but
702 * the kernel resource tree doesn't allow overlaps.
703 */
704 if (resource_overlaps(res1, res2)) {
705 res2->start = min(res1->start, res2->start);
706 res2->end = max(res1->end, res2->end);
707 dev_info(dev, "host bridge window expanded to %pR; %pR ignored\n",
708 res2, res1);
709 free = true;
710 goto next;
711 }
712 }
713
714next:
715 resource_list_del(entry);
716 if (free)
717 resource_list_free_entry(entry);
718 else
719 resource_list_add_tail(entry, resources);
720 }
721}
722
723int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info)
724{
725 int ret;
726 struct list_head *list = &info->resources;
727 struct acpi_device *device = info->bridge;
728 struct resource_entry *entry, *tmp;
729 unsigned long flags;
730
731 flags = IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_MEM_8AND16BIT;
732 ret = acpi_dev_get_resources(device, list,
733 acpi_dev_filter_resource_type_cb,
734 (void *)flags);
735 if (ret < 0)
736 dev_warn(&device->dev,
737 "failed to parse _CRS method, error code %d\n", ret);
738 else if (ret == 0)
739 dev_dbg(&device->dev,
740 "no IO and memory resources present in _CRS\n");
741 else {
742 resource_list_for_each_entry_safe(entry, tmp, list) {
743 if (entry->res->flags & IORESOURCE_DISABLED)
744 resource_list_destroy_entry(entry);
745 else
746 entry->res->name = info->name;
747 }
748 acpi_pci_root_validate_resources(&device->dev, list,
749 IORESOURCE_MEM);
750 acpi_pci_root_validate_resources(&device->dev, list,
751 IORESOURCE_IO);
752 }
753
754 return ret;
755}
756
757static void pci_acpi_root_add_resources(struct acpi_pci_root_info *info)
758{
759 struct resource_entry *entry, *tmp;
760 struct resource *res, *conflict, *root = NULL;
761
762 resource_list_for_each_entry_safe(entry, tmp, &info->resources) {
763 res = entry->res;
764 if (res->flags & IORESOURCE_MEM)
765 root = &iomem_resource;
766 else if (res->flags & IORESOURCE_IO)
767 root = &ioport_resource;
768 else
769 continue;
770
771 conflict = insert_resource_conflict(root, res);
772 if (conflict) {
773 dev_info(&info->bridge->dev,
774 "ignoring host bridge window %pR (conflicts with %s %pR)\n",
775 res, conflict->name, conflict);
776 resource_list_destroy_entry(entry);
777 }
778 }
779}
780
781static void __acpi_pci_root_release_info(struct acpi_pci_root_info *info)
782{
783 struct resource *res;
784 struct resource_entry *entry, *tmp;
785
786 if (!info)
787 return;
788
789 resource_list_for_each_entry_safe(entry, tmp, &info->resources) {
790 res = entry->res;
791 if (res->parent &&
792 (res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
793 release_resource(res);
794 resource_list_destroy_entry(entry);
795 }
796
797 info->ops->release_info(info);
798}
799
800static void acpi_pci_root_release_info(struct pci_host_bridge *bridge)
801{
802 struct resource *res;
803 struct resource_entry *entry;
804
805 resource_list_for_each_entry(entry, &bridge->windows) {
806 res = entry->res;
807 if (res->parent &&
808 (res->flags & (IORESOURCE_MEM | IORESOURCE_IO)))
809 release_resource(res);
810 }
811 __acpi_pci_root_release_info(bridge->release_data);
812}
813
814struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
815 struct acpi_pci_root_ops *ops,
816 struct acpi_pci_root_info *info,
817 void *sysdata)
818{
819 int ret, busnum = root->secondary.start;
820 struct acpi_device *device = root->device;
821 int node = acpi_get_node(device->handle);
822 struct pci_bus *bus;
823
824 info->root = root;
825 info->bridge = device;
826 info->ops = ops;
827 INIT_LIST_HEAD(&info->resources);
828 snprintf(info->name, sizeof(info->name), "PCI Bus %04x:%02x",
829 root->segment, busnum);
830
831 if (ops->init_info && ops->init_info(info))
832 goto out_release_info;
833 if (ops->prepare_resources)
834 ret = ops->prepare_resources(info);
835 else
836 ret = acpi_pci_probe_root_resources(info);
837 if (ret < 0)
838 goto out_release_info;
839
840 pci_acpi_root_add_resources(info);
841 pci_add_resource(&info->resources, &root->secondary);
842 bus = pci_create_root_bus(NULL, busnum, ops->pci_ops,
843 sysdata, &info->resources);
844 if (!bus)
845 goto out_release_info;
846
847 pci_scan_child_bus(bus);
848 pci_set_host_bridge_release(to_pci_host_bridge(bus->bridge),
849 acpi_pci_root_release_info, info);
850 if (node != NUMA_NO_NODE)
851 dev_printk(KERN_DEBUG, &bus->dev, "on NUMA node %d\n", node);
852 return bus;
853
854out_release_info:
855 __acpi_pci_root_release_info(info);
856 return NULL;
857}
858
655void __init acpi_pci_root_init(void) 859void __init acpi_pci_root_init(void)
656{ 860{
657 acpi_hest_init(); 861 acpi_hest_init();
diff --git a/include/linux/pci-acpi.h b/include/linux/pci-acpi.h
index a965efa52152..89ab0572dbc6 100644
--- a/include/linux/pci-acpi.h
+++ b/include/linux/pci-acpi.h
@@ -52,6 +52,30 @@ static inline acpi_handle acpi_pci_get_bridge_handle(struct pci_bus *pbus)
52 return ACPI_HANDLE(dev); 52 return ACPI_HANDLE(dev);
53} 53}
54 54
55struct acpi_pci_root;
56struct acpi_pci_root_ops;
57
58struct acpi_pci_root_info {
59 struct acpi_pci_root *root;
60 struct acpi_device *bridge;
61 struct acpi_pci_root_ops *ops;
62 struct list_head resources;
63 char name[16];
64};
65
66struct acpi_pci_root_ops {
67 struct pci_ops *pci_ops;
68 int (*init_info)(struct acpi_pci_root_info *info);
69 void (*release_info)(struct acpi_pci_root_info *info);
70 int (*prepare_resources)(struct acpi_pci_root_info *info);
71};
72
73extern int acpi_pci_probe_root_resources(struct acpi_pci_root_info *info);
74extern struct pci_bus *acpi_pci_root_create(struct acpi_pci_root *root,
75 struct acpi_pci_root_ops *ops,
76 struct acpi_pci_root_info *info,
77 void *sd);
78
55void acpi_pci_add_bus(struct pci_bus *bus); 79void acpi_pci_add_bus(struct pci_bus *bus);
56void acpi_pci_remove_bus(struct pci_bus *bus); 80void acpi_pci_remove_bus(struct pci_bus *bus);
57 81