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