aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/setup-bus.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/setup-bus.c')
-rw-r--r--drivers/pci/setup-bus.c95
1 files changed, 79 insertions, 16 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 8169597e47cb..4fd0cacf7ca0 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -99,8 +99,8 @@ static void remove_from_list(struct list_head *head,
99 } 99 }
100} 100}
101 101
102static resource_size_t get_res_add_size(struct list_head *head, 102static struct pci_dev_resource *res_to_dev_res(struct list_head *head,
103 struct resource *res) 103 struct resource *res)
104{ 104{
105 struct pci_dev_resource *dev_res; 105 struct pci_dev_resource *dev_res;
106 106
@@ -109,17 +109,37 @@ static resource_size_t get_res_add_size(struct list_head *head,
109 int idx = res - &dev_res->dev->resource[0]; 109 int idx = res - &dev_res->dev->resource[0];
110 110
111 dev_printk(KERN_DEBUG, &dev_res->dev->dev, 111 dev_printk(KERN_DEBUG, &dev_res->dev->dev,
112 "res[%d]=%pR get_res_add_size add_size %llx\n", 112 "res[%d]=%pR res_to_dev_res add_size %llx min_align %llx\n",
113 idx, dev_res->res, 113 idx, dev_res->res,
114 (unsigned long long)dev_res->add_size); 114 (unsigned long long)dev_res->add_size,
115 (unsigned long long)dev_res->min_align);
115 116
116 return dev_res->add_size; 117 return dev_res;
117 } 118 }
118 } 119 }
119 120
120 return 0; 121 return NULL;
121} 122}
122 123
124static resource_size_t get_res_add_size(struct list_head *head,
125 struct resource *res)
126{
127 struct pci_dev_resource *dev_res;
128
129 dev_res = res_to_dev_res(head, res);
130 return dev_res ? dev_res->add_size : 0;
131}
132
133static resource_size_t get_res_add_align(struct list_head *head,
134 struct resource *res)
135{
136 struct pci_dev_resource *dev_res;
137
138 dev_res = res_to_dev_res(head, res);
139 return dev_res ? dev_res->min_align : 0;
140}
141
142
123/* Sort resources by alignment */ 143/* Sort resources by alignment */
124static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head) 144static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head)
125{ 145{
@@ -215,7 +235,7 @@ static void reassign_resources_sorted(struct list_head *realloc_head,
215 struct resource *res; 235 struct resource *res;
216 struct pci_dev_resource *add_res, *tmp; 236 struct pci_dev_resource *add_res, *tmp;
217 struct pci_dev_resource *dev_res; 237 struct pci_dev_resource *dev_res;
218 resource_size_t add_size; 238 resource_size_t add_size, align;
219 int idx; 239 int idx;
220 240
221 list_for_each_entry_safe(add_res, tmp, realloc_head, list) { 241 list_for_each_entry_safe(add_res, tmp, realloc_head, list) {
@@ -238,13 +258,13 @@ static void reassign_resources_sorted(struct list_head *realloc_head,
238 258
239 idx = res - &add_res->dev->resource[0]; 259 idx = res - &add_res->dev->resource[0];
240 add_size = add_res->add_size; 260 add_size = add_res->add_size;
261 align = add_res->min_align;
241 if (!resource_size(res)) { 262 if (!resource_size(res)) {
242 res->start = add_res->start; 263 res->start = align;
243 res->end = res->start + add_size - 1; 264 res->end = res->start + add_size - 1;
244 if (pci_assign_resource(add_res->dev, idx)) 265 if (pci_assign_resource(add_res->dev, idx))
245 reset_resource(res); 266 reset_resource(res);
246 } else { 267 } else {
247 resource_size_t align = add_res->min_align;
248 res->flags |= add_res->flags & 268 res->flags |= add_res->flags &
249 (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN); 269 (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN);
250 if (pci_reassign_resource(add_res->dev, idx, 270 if (pci_reassign_resource(add_res->dev, idx,
@@ -368,8 +388,9 @@ static void __assign_resources_sorted(struct list_head *head,
368 LIST_HEAD(save_head); 388 LIST_HEAD(save_head);
369 LIST_HEAD(local_fail_head); 389 LIST_HEAD(local_fail_head);
370 struct pci_dev_resource *save_res; 390 struct pci_dev_resource *save_res;
371 struct pci_dev_resource *dev_res, *tmp_res; 391 struct pci_dev_resource *dev_res, *tmp_res, *dev_res2;
372 unsigned long fail_type; 392 unsigned long fail_type;
393 resource_size_t add_align, align;
373 394
374 /* Check if optional add_size is there */ 395 /* Check if optional add_size is there */
375 if (!realloc_head || list_empty(realloc_head)) 396 if (!realloc_head || list_empty(realloc_head))
@@ -384,10 +405,44 @@ static void __assign_resources_sorted(struct list_head *head,
384 } 405 }
385 406
386 /* Update res in head list with add_size in realloc_head list */ 407 /* Update res in head list with add_size in realloc_head list */
387 list_for_each_entry(dev_res, head, list) 408 list_for_each_entry_safe(dev_res, tmp_res, head, list) {
388 dev_res->res->end += get_res_add_size(realloc_head, 409 dev_res->res->end += get_res_add_size(realloc_head,
389 dev_res->res); 410 dev_res->res);
390 411
412 /*
413 * There are two kinds of additional resources in the list:
414 * 1. bridge resource -- IORESOURCE_STARTALIGN
415 * 2. SR-IOV resource -- IORESOURCE_SIZEALIGN
416 * Here just fix the additional alignment for bridge
417 */
418 if (!(dev_res->res->flags & IORESOURCE_STARTALIGN))
419 continue;
420
421 add_align = get_res_add_align(realloc_head, dev_res->res);
422
423 /*
424 * The "head" list is sorted by the alignment to make sure
425 * resources with bigger alignment will be assigned first.
426 * After we change the alignment of a dev_res in "head" list,
427 * we need to reorder the list by alignment to make it
428 * consistent.
429 */
430 if (add_align > dev_res->res->start) {
431 dev_res->res->start = add_align;
432 dev_res->res->end = add_align +
433 resource_size(dev_res->res);
434
435 list_for_each_entry(dev_res2, head, list) {
436 align = pci_resource_alignment(dev_res2->dev,
437 dev_res2->res);
438 if (add_align > align)
439 list_move_tail(&dev_res->list,
440 &dev_res2->list);
441 }
442 }
443
444 }
445
391 /* Try updated head list with add_size added */ 446 /* Try updated head list with add_size added */
392 assign_requested_resources_sorted(head, &local_fail_head); 447 assign_requested_resources_sorted(head, &local_fail_head);
393 448
@@ -962,6 +1017,8 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
962 struct resource *b_res = find_free_bus_resource(bus, 1017 struct resource *b_res = find_free_bus_resource(bus,
963 mask | IORESOURCE_PREFETCH, type); 1018 mask | IORESOURCE_PREFETCH, type);
964 resource_size_t children_add_size = 0; 1019 resource_size_t children_add_size = 0;
1020 resource_size_t children_add_align = 0;
1021 resource_size_t add_align = 0;
965 1022
966 if (!b_res) 1023 if (!b_res)
967 return -ENOSPC; 1024 return -ENOSPC;
@@ -986,6 +1043,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
986 /* put SRIOV requested res to the optional list */ 1043 /* put SRIOV requested res to the optional list */
987 if (realloc_head && i >= PCI_IOV_RESOURCES && 1044 if (realloc_head && i >= PCI_IOV_RESOURCES &&
988 i <= PCI_IOV_RESOURCE_END) { 1045 i <= PCI_IOV_RESOURCE_END) {
1046 add_align = max(pci_resource_alignment(dev, r), add_align);
989 r->end = r->start - 1; 1047 r->end = r->start - 1;
990 add_to_list(realloc_head, dev, r, r_size, 0/* don't care */); 1048 add_to_list(realloc_head, dev, r, r_size, 0/* don't care */);
991 children_add_size += r_size; 1049 children_add_size += r_size;
@@ -1016,19 +1074,23 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
1016 if (order > max_order) 1074 if (order > max_order)
1017 max_order = order; 1075 max_order = order;
1018 1076
1019 if (realloc_head) 1077 if (realloc_head) {
1020 children_add_size += get_res_add_size(realloc_head, r); 1078 children_add_size += get_res_add_size(realloc_head, r);
1079 children_add_align = get_res_add_align(realloc_head, r);
1080 add_align = max(add_align, children_add_align);
1081 }
1021 } 1082 }
1022 } 1083 }
1023 1084
1024 min_align = calculate_mem_align(aligns, max_order); 1085 min_align = calculate_mem_align(aligns, max_order);
1025 min_align = max(min_align, window_alignment(bus, b_res->flags)); 1086 min_align = max(min_align, window_alignment(bus, b_res->flags));
1026 size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align); 1087 size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align);
1088 add_align = max(min_align, add_align);
1027 if (children_add_size > add_size) 1089 if (children_add_size > add_size)
1028 add_size = children_add_size; 1090 add_size = children_add_size;
1029 size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 : 1091 size1 = (!realloc_head || (realloc_head && !add_size)) ? size0 :
1030 calculate_memsize(size, min_size, add_size, 1092 calculate_memsize(size, min_size, add_size,
1031 resource_size(b_res), min_align); 1093 resource_size(b_res), add_align);
1032 if (!size0 && !size1) { 1094 if (!size0 && !size1) {
1033 if (b_res->start || b_res->end) 1095 if (b_res->start || b_res->end)
1034 dev_info(&bus->self->dev, "disabling bridge window %pR to %pR (unused)\n", 1096 dev_info(&bus->self->dev, "disabling bridge window %pR to %pR (unused)\n",
@@ -1040,10 +1102,11 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
1040 b_res->end = size0 + min_align - 1; 1102 b_res->end = size0 + min_align - 1;
1041 b_res->flags |= IORESOURCE_STARTALIGN; 1103 b_res->flags |= IORESOURCE_STARTALIGN;
1042 if (size1 > size0 && realloc_head) { 1104 if (size1 > size0 && realloc_head) {
1043 add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align); 1105 add_to_list(realloc_head, bus->self, b_res, size1-size0, add_align);
1044 dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window %pR to %pR add_size %llx\n", 1106 dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window %pR to %pR add_size %llx add_align %llx\n",
1045 b_res, &bus->busn_res, 1107 b_res, &bus->busn_res,
1046 (unsigned long long)size1-size0); 1108 (unsigned long long) (size1 - size0),
1109 (unsigned long long) add_align);
1047 } 1110 }
1048 return 0; 1111 return 0;
1049} 1112}