summaryrefslogtreecommitdiff
path: root/drivers/pci
diff options
context:
space:
mode:
authorYinghai Lu <yinghai@kernel.org>2011-07-26 00:08:38 +0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2011-08-01 22:49:39 +0400
commitbe768912a49b10b68e96fbd8fa3cab0adfbd3091 (patch)
treed1414e67c840bd66fef1d92177d41a2c22529015 /drivers/pci
parentb03e7495a862b028294f59fc87286d6d78ee7fa1 (diff)
downloadlinux-be768912a49b10b68e96fbd8fa3cab0adfbd3091.tar.xz
PCI: honor child buses add_size in hot plug configuration
git commit c8adf9a3e873eddaaec11ac410a99ef6b9656938 "PCI: pre-allocate additional resources to devices only after successful allocation of essential resources." fails to take into consideration the optional-resources needed by children devices while calculating the optional-resource needed by the bridge. This can be a problem on some setup. For example, if a hotplug bridge has 8 children hotplug bridges, the bridge should have enough resources to accomodate the hotplug requirements for each of its children hotplug bridges. Currently this is not the case. This patch fixes the problem. Signed-off-by: Yinghai Lu <yinghai@kernel.org> Reviewed-by: Ram Pai <linuxram@us.ibm.com> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/setup-bus.c26
1 files changed, 26 insertions, 0 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index 8a1d3c7863a8..4409cd0e15fa 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -540,6 +540,20 @@ static resource_size_t calculate_memsize(resource_size_t size,
return size;
}
+static resource_size_t get_res_add_size(struct resource_list_x *add_head,
+ struct resource *res)
+{
+ struct resource_list_x *list;
+
+ /* check if it is in add_head list */
+ for (list = add_head->next; list && list->res != res;
+ list = list->next);
+ if (list)
+ return list->add_size;
+
+ return 0;
+}
+
/**
* pbus_size_io() - size the io window of a given bus
*
@@ -559,6 +573,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
struct pci_dev *dev;
struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
unsigned long size = 0, size0 = 0, size1 = 0;
+ resource_size_t children_add_size = 0;
if (!b_res)
return;
@@ -579,10 +594,15 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
size += r_size;
else
size1 += r_size;
+
+ if (add_head)
+ children_add_size += get_res_add_size(add_head, r);
}
}
size0 = calculate_iosize(size, min_size, size1,
resource_size(b_res), 4096);
+ if (children_add_size > add_size)
+ add_size = children_add_size;
size1 = (!add_head || (add_head && !add_size)) ? size0 :
calculate_iosize(size, min_size+add_size, size1,
resource_size(b_res), 4096);
@@ -624,6 +644,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
int order, max_order;
struct resource *b_res = find_free_bus_resource(bus, type);
unsigned int mem64_mask = 0;
+ resource_size_t children_add_size = 0;
if (!b_res)
return 0;
@@ -665,6 +686,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
if (order > max_order)
max_order = order;
mem64_mask &= r->flags & IORESOURCE_MEM_64;
+
+ if (add_head)
+ children_add_size += get_res_add_size(add_head, r);
}
}
align = 0;
@@ -681,6 +705,8 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
align += aligns[order];
}
size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align);
+ if (children_add_size > add_size)
+ add_size = children_add_size;
size1 = (!add_head || (add_head && !add_size)) ? size0 :
calculate_memsize(size, min_size+add_size, 0,
resource_size(b_res), min_align);