aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWei Yang <weiyang@linux.vnet.ibm.com>2015-03-25 04:23:51 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2015-03-30 22:02:37 -0400
commitd74b9027a4dafa44d3a3c2a44ce135e50a13ec10 (patch)
tree7f7bedddc7287c1a8415f4ae37fa16c6ec5206ef
parent978d2d68312326b715a5913aaab1eaf24fe99108 (diff)
PCI: Consider additional PF's IOV BAR alignment in sizing and assigning
When sizing and assigning resources, we divide the resources into two lists: the requested list and the additional list. We don't consider the alignment of additional VF(n) BAR space. This is because the alignment required for the VF(n) BAR space is the size of an individual VF BAR, not the size of the space for *all* VFs. But we want additional alignment to support partitioning on PowerNV. Consider the additional IOV BAR alignment when sizing and assigning resources. When there is not enough system MMIO space to accomodate both the requested list and the additional list, the PF's IOV BAR alignment will not contribute to the bridge. When there is enough system MMIO space for both lists, the additional alignment will contribute to the bridge. The additional alignment is stored in the min_align of pci_dev_resource, which is stored in the additional list by add_to_list() at the end of pbus_size_mem(). The additional alignment is calculated in pci_resource_alignment(). For an IOV BAR, we have arch dependent function to get the alignment for different arch. [bhelgaas: changelog, printk cast] Signed-off-by: Wei Yang <weiyang@linux.vnet.ibm.com> Acked-by: Bjorn Helgaas <bhelgaas@google.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-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 e3e17f3c0f0f..6603d401bb7c 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}