]>
Commit | Line | Data |
---|---|---|
b2441318 | 1 | // SPDX-License-Identifier: GPL-2.0 |
67f241f4 YL |
2 | #include <linux/init.h> |
3 | #include <linux/pci.h> | |
9ad3f2c7 | 4 | #include <linux/range.h> |
67f241f4 YL |
5 | |
6 | #include "bus_numa.h" | |
7 | ||
d28e5ac2 | 8 | LIST_HEAD(pci_root_infos); |
67f241f4 | 9 | |
d28e5ac2 | 10 | static struct pci_root_info *x86_find_pci_root_info(int bus) |
67f241f4 | 11 | { |
67f241f4 YL |
12 | struct pci_root_info *info; |
13 | ||
d28e5ac2 | 14 | list_for_each_entry(info, &pci_root_infos, list) |
a10bb128 | 15 | if (info->busn.start == bus) |
d28e5ac2 YL |
16 | return info; |
17 | ||
18 | return NULL; | |
19 | } | |
67f241f4 | 20 | |
afcf21c2 BH |
21 | int x86_pci_root_bus_node(int bus) |
22 | { | |
23 | struct pci_root_info *info = x86_find_pci_root_info(bus); | |
24 | ||
25 | if (!info) | |
26 | return NUMA_NO_NODE; | |
27 | ||
28 | return info->node; | |
29 | } | |
30 | ||
d28e5ac2 YL |
31 | void x86_pci_root_bus_resources(int bus, struct list_head *resources) |
32 | { | |
33 | struct pci_root_info *info = x86_find_pci_root_info(bus); | |
34 | struct pci_root_res *root_res; | |
14d76b68 | 35 | struct resource_entry *window; |
a10bb128 | 36 | bool found = false; |
d28e5ac2 YL |
37 | |
38 | if (!info) | |
2cd6975a | 39 | goto default_resources; |
67f241f4 | 40 | |
2cd6975a BH |
41 | printk(KERN_DEBUG "PCI: root bus %02x: hardware-probed resources\n", |
42 | bus); | |
67f241f4 | 43 | |
a10bb128 | 44 | /* already added by acpi ? */ |
14d76b68 | 45 | resource_list_for_each_entry(window, resources) |
a10bb128 YL |
46 | if (window->res->flags & IORESOURCE_BUS) { |
47 | found = true; | |
48 | break; | |
49 | } | |
50 | ||
51 | if (!found) | |
52 | pci_add_resource(resources, &info->busn); | |
53 | ||
727ae8be LJ |
54 | list_for_each_entry(root_res, &info->resources, list) |
55 | pci_add_resource(resources, &root_res->res); | |
56 | ||
2cd6975a BH |
57 | return; |
58 | ||
59 | default_resources: | |
60 | /* | |
61 | * We don't have any host bridge aperture information from the | |
62 | * "native host bridge drivers," e.g., amd_bus or broadcom_bus, | |
63 | * so fall back to the defaults historically used by pci_create_bus(). | |
64 | */ | |
65 | printk(KERN_DEBUG "PCI: root bus %02x: using default resources\n", bus); | |
66 | pci_add_resource(resources, &ioport_resource); | |
67 | pci_add_resource(resources, &iomem_resource); | |
67f241f4 YL |
68 | } |
69 | ||
d28e5ac2 YL |
70 | struct pci_root_info __init *alloc_pci_root_info(int bus_min, int bus_max, |
71 | int node, int link) | |
72 | { | |
73 | struct pci_root_info *info; | |
74 | ||
75 | info = kzalloc(sizeof(*info), GFP_KERNEL); | |
76 | ||
77 | if (!info) | |
78 | return info; | |
79 | ||
a10bb128 YL |
80 | sprintf(info->name, "PCI Bus #%02x", bus_min); |
81 | ||
d28e5ac2 | 82 | INIT_LIST_HEAD(&info->resources); |
a10bb128 YL |
83 | info->busn.name = info->name; |
84 | info->busn.start = bus_min; | |
85 | info->busn.end = bus_max; | |
86 | info->busn.flags = IORESOURCE_BUS; | |
d28e5ac2 YL |
87 | info->node = node; |
88 | info->link = link; | |
89 | ||
90 | list_add_tail(&info->list, &pci_root_infos); | |
91 | ||
92 | return info; | |
93 | } | |
94 | ||
a18e3690 GKH |
95 | void update_res(struct pci_root_info *info, resource_size_t start, |
96 | resource_size_t end, unsigned long flags, int merge) | |
67f241f4 | 97 | { |
67f241f4 | 98 | struct resource *res; |
d28e5ac2 | 99 | struct pci_root_res *root_res; |
67f241f4 YL |
100 | |
101 | if (start > end) | |
102 | return; | |
103 | ||
9ad3f2c7 YL |
104 | if (start == MAX_RESOURCE) |
105 | return; | |
106 | ||
67f241f4 YL |
107 | if (!merge) |
108 | goto addit; | |
109 | ||
110 | /* try to merge it with old one */ | |
d28e5ac2 | 111 | list_for_each_entry(root_res, &info->resources, list) { |
b74fd238 YL |
112 | resource_size_t final_start, final_end; |
113 | resource_size_t common_start, common_end; | |
67f241f4 | 114 | |
d28e5ac2 | 115 | res = &root_res->res; |
67f241f4 YL |
116 | if (res->flags != flags) |
117 | continue; | |
118 | ||
b74fd238 YL |
119 | common_start = max(res->start, start); |
120 | common_end = min(res->end, end); | |
67f241f4 YL |
121 | if (common_start > common_end + 1) |
122 | continue; | |
123 | ||
b74fd238 YL |
124 | final_start = min(res->start, start); |
125 | final_end = max(res->end, end); | |
67f241f4 YL |
126 | |
127 | res->start = final_start; | |
128 | res->end = final_end; | |
129 | return; | |
130 | } | |
131 | ||
132 | addit: | |
133 | ||
134 | /* need to add that */ | |
d28e5ac2 YL |
135 | root_res = kzalloc(sizeof(*root_res), GFP_KERNEL); |
136 | if (!root_res) | |
67f241f4 YL |
137 | return; |
138 | ||
d28e5ac2 | 139 | res = &root_res->res; |
67f241f4 YL |
140 | res->name = info->name; |
141 | res->flags = flags; | |
142 | res->start = start; | |
143 | res->end = end; | |
d28e5ac2 YL |
144 | |
145 | list_add_tail(&root_res->list, &info->resources); | |
67f241f4 | 146 | } |