Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bdc4abec authored by Yinghai Lu's avatar Yinghai Lu Committed by Jesse Barnes
Browse files

PCI: Replace resource_list with generic list



So we can use helper functions for generic list.  This makes the
resource re-allocation code much more readable.

-v2: Use list_add_tail instead of adding list_insert_before, Pointed out
     by Linus.

Suggested-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: default avatarYinghai Lu <yinghai@kernel.org>
Signed-off-by: default avatarJesse Barnes <jbarnes@virtuousgeek.org>
parent 2934a0de
Loading
Loading
Loading
Loading
+182 −192
Original line number Original line Diff line number Diff line
@@ -27,14 +27,14 @@
#include <linux/slab.h>
#include <linux/slab.h>
#include "pci.h"
#include "pci.h"


struct resource_list {
struct pci_dev_resource {
	struct resource_list *next;
	struct list_head list;
	struct resource *res;
	struct resource *res;
	struct pci_dev *dev;
	struct pci_dev *dev;
};
};


struct resource_list_x {
struct pci_dev_resource_x {
	struct resource_list_x *next;
	struct list_head list;
	struct resource *res;
	struct resource *res;
	struct pci_dev *dev;
	struct pci_dev *dev;
	resource_size_t start;
	resource_size_t start;
@@ -45,13 +45,11 @@ struct resource_list_x {
};
};


#define free_list(type, head) do {				\
#define free_list(type, head) do {				\
	struct type *list, *tmp;			\
	struct type *dev_res, *tmp;				\
	for (list = (head)->next; list;) {		\
	list_for_each_entry_safe(dev_res, tmp, head, list) {	\
		tmp = list;				\
		list_del(&dev_res->list);			\
		list = list->next;			\
		kfree(dev_res);					\
		kfree(tmp);				\
	}							\
	}							\
	(head)->next = NULL;				\
} while (0)
} while (0)


int pci_realloc_enable = 0;
int pci_realloc_enable = 0;
@@ -70,21 +68,18 @@ void pci_realloc(void)
 * @add_size:	additional size to be optionally added
 * @add_size:	additional size to be optionally added
 *              to the resource
 *              to the resource
 */
 */
static int add_to_list(struct resource_list_x *head,
static int add_to_list(struct list_head *head,
		 struct pci_dev *dev, struct resource *res,
		 struct pci_dev *dev, struct resource *res,
		 resource_size_t add_size, resource_size_t min_align)
		 resource_size_t add_size, resource_size_t min_align)
{
{
	struct resource_list_x *list = head;
	struct pci_dev_resource_x *tmp;
	struct resource_list_x *ln = list->next;
	struct resource_list_x *tmp;


	tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
	tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
	if (!tmp) {
	if (!tmp) {
		pr_warning("add_to_list: kmalloc() failed!\n");
		pr_warning("add_to_list: kmalloc() failed!\n");
		return -ENOMEM;
		return -ENOMEM;
	}
	}


	tmp->next = ln;
	tmp->res = res;
	tmp->res = res;
	tmp->dev = dev;
	tmp->dev = dev;
	tmp->start = res->start;
	tmp->start = res->start;
@@ -92,12 +87,13 @@ static int add_to_list(struct resource_list_x *head,
	tmp->flags = res->flags;
	tmp->flags = res->flags;
	tmp->add_size = add_size;
	tmp->add_size = add_size;
	tmp->min_align = min_align;
	tmp->min_align = min_align;
	list->next = tmp;

	list_add(&tmp->list, head);


	return 0;
	return 0;
}
}


static void add_to_failed_list(struct resource_list_x *head,
static void add_to_failed_list(struct list_head *head,
				struct pci_dev *dev, struct resource *res)
				struct pci_dev *dev, struct resource *res)
{
{
	add_to_list(head, dev, res,
	add_to_list(head, dev, res,
@@ -105,53 +101,48 @@ static void add_to_failed_list(struct resource_list_x *head,
			0 /* dont care */);
			0 /* dont care */);
}
}


static void remove_from_list(struct resource_list_x *realloc_head,
static void remove_from_list(struct list_head *realloc_head,
				 struct resource *res)
				 struct resource *res)
{
{
	struct resource_list_x *prev, *tmp, *list;
	struct pci_dev_resource_x *dev_res_x, *tmp;


	prev = realloc_head;
	list_for_each_entry_safe(dev_res_x, tmp, realloc_head, list) {
	for (list = realloc_head->next; list;) {
		if (dev_res_x->res == res) {
		if (list->res != res) {
			list_del(&dev_res_x->list);
			prev = list;
			kfree(dev_res_x);
			list = list->next;
			break;
			continue;
		}
		}
		tmp = list;
		prev->next = list = list->next;
		kfree(tmp);
	}
	}
}
}


static resource_size_t get_res_add_size(struct resource_list_x *realloc_head,
static resource_size_t get_res_add_size(struct list_head *realloc_head,
					struct resource *res)
					struct resource *res)
{
{
	struct resource_list_x *list;
	struct pci_dev_resource_x *dev_res_x;


	/* check if it is in realloc_head list */
	list_for_each_entry(dev_res_x, realloc_head, list) {
	for (list = realloc_head->next; list && list->res != res;
		if (dev_res_x->res == res) {
			list = list->next)
			dev_printk(KERN_DEBUG, &dev_res_x->dev->dev,
		;

	if (list) {
		dev_printk(KERN_DEBUG, &list->dev->dev,
				 "%pR get_res_add_size  add_size %llx\n",
				 "%pR get_res_add_size  add_size %llx\n",
			 list->res, (unsigned long long)list->add_size);
				 dev_res_x->res,
		return list->add_size;
				 (unsigned long long)dev_res_x->add_size);
			return dev_res_x->add_size;
		}
	}
	}


	return 0;
	return 0;
}
}


/* Sort resources by alignment */
/* Sort resources by alignment */
static void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head)
{
{
	int i;
	int i;


	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
		struct resource *r;
		struct resource *r;
		struct resource_list *list, *tmp;
		struct pci_dev_resource *dev_res, *tmp;
		resource_size_t r_align;
		resource_size_t r_align;
		struct list_head *n;


		r = &dev->resource[i];
		r = &dev->resource[i];


@@ -167,30 +158,34 @@ static void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
				 i, r);
				 i, r);
			continue;
			continue;
		}
		}
		for (list = head; ; list = list->next) {
			resource_size_t align = 0;
			struct resource_list *ln = list->next;

			if (ln)
				align = pci_resource_alignment(ln->dev, ln->res);


			if (r_align > align) {
		tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
				tmp = kmalloc(sizeof(*tmp), GFP_KERNEL);
		if (!tmp)
		if (!tmp)
			panic("pdev_sort_resources(): "
			panic("pdev_sort_resources(): "
			      "kmalloc() failed!\n");
			      "kmalloc() failed!\n");
				tmp->next = ln;
		tmp->res = r;
		tmp->res = r;
		tmp->dev = dev;
		tmp->dev = dev;
				list->next = tmp;

		/* fallback is smallest one or list is empty*/
		n = head;
		list_for_each_entry(dev_res, head, list) {
			resource_size_t align;

			align = pci_resource_alignment(dev_res->dev,
							 dev_res->res);

			if (r_align > align) {
				n = &dev_res->list;
				break;
				break;
			}
			}
		}
		}
		/* Insert it just before n*/
		list_add_tail(&tmp->list, n);
	}
	}
}
}


static void __dev_sort_resources(struct pci_dev *dev,
static void __dev_sort_resources(struct pci_dev *dev,
				 struct resource_list *head)
				 struct list_head *head)
{
{
	u16 class = dev->class >> 8;
	u16 class = dev->class >> 8;


@@ -228,49 +223,53 @@ static inline void reset_resource(struct resource *res)
 * additional resources for the element, provided the element
 * additional resources for the element, provided the element
 * is in the head list.
 * is in the head list.
 */
 */
static void reassign_resources_sorted(struct resource_list_x *realloc_head,
static void reassign_resources_sorted(struct list_head *realloc_head,
		struct resource_list *head)
		struct list_head *head)
{
{
	struct resource *res;
	struct resource *res;
	struct resource_list_x *list, *tmp, *prev;
	struct pci_dev_resource_x *dev_res_x, *tmp;
	struct resource_list *hlist;
	struct pci_dev_resource *dev_res;
	resource_size_t add_size;
	resource_size_t add_size;
	int idx;
	int idx;


	prev = realloc_head;
	list_for_each_entry_safe(dev_res_x, tmp, realloc_head, list) {
	for (list = realloc_head->next; list;) {
		bool found_match = false;
		res = list->res;

		res = dev_res_x->res;
		/* skip resource that has been reset */
		/* skip resource that has been reset */
		if (!res->flags)
		if (!res->flags)
			goto out;
			goto out;


		/* skip this resource if not found in head list */
		/* skip this resource if not found in head list */
		for (hlist = head->next; hlist && hlist->res != res;
		list_for_each_entry(dev_res, head, list) {
				hlist = hlist->next);
			if (dev_res->res == res) {
		if (!hlist) { /* just skip */
				found_match = true;
			prev = list;
				break;
			list = list->next;
			}
			continue;
		}
		}
		if (!found_match)/* just skip */
			continue;


		idx = res - &list->dev->resource[0];
		idx = res - &dev_res_x->dev->resource[0];
		add_size=list->add_size;
		add_size = dev_res_x->add_size;
		if (!resource_size(res)) {
		if (!resource_size(res)) {
			res->start = list->start;
			res->start = dev_res_x->start;
			res->end = res->start + add_size - 1;
			res->end = res->start + add_size - 1;
			if(pci_assign_resource(list->dev, idx))
			if (pci_assign_resource(dev_res_x->dev, idx))
				reset_resource(res);
				reset_resource(res);
		} else {
		} else {
			resource_size_t align = list->min_align;
			resource_size_t align = dev_res_x->min_align;
			res->flags |= list->flags & (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN);
			res->flags |= dev_res_x->flags &
			if (pci_reassign_resource(list->dev, idx, add_size, align))
				 (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN);
				dev_printk(KERN_DEBUG, &list->dev->dev, "failed to add optional resources res=%pR\n",
			if (pci_reassign_resource(dev_res_x->dev, idx,
						  add_size, align))
				dev_printk(KERN_DEBUG, &dev_res_x->dev->dev,
				   "failed to add optional resources res=%pR\n",
							res);
							res);
		}
		}
out:
out:
		tmp = list;
		list_del(&dev_res_x->list);
		prev->next = list = list->next;
		kfree(dev_res_x);
		kfree(tmp);
	}
	}
}
}


@@ -284,34 +283,36 @@ static void reassign_resources_sorted(struct resource_list_x *realloc_head,
 * Satisfy resource requests of each element in the list. Add
 * Satisfy resource requests of each element in the list. Add
 * requests that could not satisfied to the failed_list.
 * requests that could not satisfied to the failed_list.
 */
 */
static void assign_requested_resources_sorted(struct resource_list *head,
static void assign_requested_resources_sorted(struct list_head *head,
				 struct resource_list_x *fail_head)
				 struct list_head *fail_head)
{
{
	struct resource *res;
	struct resource *res;
	struct resource_list *list;
	struct pci_dev_resource *dev_res;
	int idx;
	int idx;


	for (list = head->next; list; list = list->next) {
	list_for_each_entry(dev_res, head, list) {
		res = list->res;
		res = dev_res->res;
		idx = res - &list->dev->resource[0];
		idx = res - &dev_res->dev->resource[0];
		if (resource_size(res) && pci_assign_resource(list->dev, idx)) {
		if (resource_size(res) &&
			if (fail_head && !pci_is_root_bus(list->dev->bus)) {
		    pci_assign_resource(dev_res->dev, idx)) {
			if (fail_head && !pci_is_root_bus(dev_res->dev->bus)) {
				/*
				/*
				 * if the failed res is for ROM BAR, and it will
				 * if the failed res is for ROM BAR, and it will
				 * be enabled later, don't add it to the list
				 * be enabled later, don't add it to the list
				 */
				 */
				if (!((idx == PCI_ROM_RESOURCE) &&
				if (!((idx == PCI_ROM_RESOURCE) &&
				      (!(res->flags & IORESOURCE_ROM_ENABLE))))
				      (!(res->flags & IORESOURCE_ROM_ENABLE))))
					add_to_failed_list(fail_head, list->dev, res);
					add_to_failed_list(fail_head,
							   dev_res->dev, res);
			}
			}
			reset_resource(res);
			reset_resource(res);
		}
		}
	}
	}
}
}


static void __assign_resources_sorted(struct resource_list *head,
static void __assign_resources_sorted(struct list_head *head,
				 struct resource_list_x *realloc_head,
				 struct list_head *realloc_head,
				 struct resource_list_x *fail_head)
				 struct list_head *fail_head)
{
{
	/*
	/*
	 * Should not assign requested resources at first.
	 * Should not assign requested resources at first.
@@ -322,53 +323,55 @@ static void __assign_resources_sorted(struct resource_list *head,
	 *  if could not do that, we still try to assign requested at first,
	 *  if could not do that, we still try to assign requested at first,
	 *    then try to reassign add_size for some resources.
	 *    then try to reassign add_size for some resources.
	 */
	 */
	struct resource_list_x save_head, local_fail_head, *list;
	LIST_HEAD(save_head);
	struct resource_list *l;
	LIST_HEAD(local_fail_head);
	struct pci_dev_resource_x *dev_res_x;
	struct pci_dev_resource *dev_res;


	/* Check if optional add_size is there */
	/* Check if optional add_size is there */
	if (!realloc_head || !realloc_head->next)
	if (!realloc_head || list_empty(realloc_head))
		goto requested_and_reassign;
		goto requested_and_reassign;


	/* Save original start, end, flags etc at first */
	/* Save original start, end, flags etc at first */
	save_head.next = NULL;
	list_for_each_entry(dev_res, head, list) {
	for (l = head->next; l; l = l->next)
		if (add_to_list(&save_head, dev_res->dev, dev_res->res, 0, 0)) {
		if (add_to_list(&save_head, l->dev, l->res, 0, 0)) {
			free_list(pci_dev_resource_x, &save_head);
			free_list(resource_list_x, &save_head);
			goto requested_and_reassign;
			goto requested_and_reassign;
		}
		}
	}


	/* Update res in head list with add_size in realloc_head list */
	/* Update res in head list with add_size in realloc_head list */
	for (l = head->next; l; l = l->next)
	list_for_each_entry(dev_res, head, list)
		l->res->end += get_res_add_size(realloc_head, l->res);
		dev_res->res->end += get_res_add_size(realloc_head,
							dev_res->res);


	/* Try updated head list with add_size added */
	/* Try updated head list with add_size added */
	local_fail_head.next = NULL;
	assign_requested_resources_sorted(head, &local_fail_head);
	assign_requested_resources_sorted(head, &local_fail_head);


	/* all assigned with add_size ? */
	/* all assigned with add_size ? */
	if (!local_fail_head.next) {
	if (list_empty(&local_fail_head)) {
		/* Remove head list from realloc_head list */
		/* Remove head list from realloc_head list */
		for (l = head->next; l; l = l->next)
		list_for_each_entry(dev_res, head, list)
			remove_from_list(realloc_head, l->res);
			remove_from_list(realloc_head, dev_res->res);
		free_list(resource_list_x, &save_head);
		free_list(pci_dev_resource_x, &save_head);
		free_list(resource_list, head);
		free_list(pci_dev_resource, head);
		return;
		return;
	}
	}


	free_list(resource_list_x, &local_fail_head);
	free_list(pci_dev_resource_x, &local_fail_head);
	/* Release assigned resource */
	/* Release assigned resource */
	for (l = head->next; l; l = l->next)
	list_for_each_entry(dev_res, head, list)
		if (l->res->parent)
		if (dev_res->res->parent)
			release_resource(l->res);
			release_resource(dev_res->res);
	/* Restore start/end/flags from saved list */
	/* Restore start/end/flags from saved list */
	for (list = save_head.next; list; list = list->next) {
	list_for_each_entry(dev_res_x, &save_head, list) {
		struct resource *res = list->res;
		struct resource *res = dev_res_x->res;


		res->start = list->start;
		res->start = dev_res_x->start;
		res->end = list->end;
		res->end = dev_res_x->end;
		res->flags = list->flags;
		res->flags = dev_res_x->flags;
	}
	}
	free_list(resource_list_x, &save_head);
	free_list(pci_dev_resource_x, &save_head);


requested_and_reassign:
requested_and_reassign:
	/* Satisfy the must-have resource requests */
	/* Satisfy the must-have resource requests */
@@ -378,29 +381,27 @@ static void __assign_resources_sorted(struct resource_list *head,
		requests */
		requests */
	if (realloc_head)
	if (realloc_head)
		reassign_resources_sorted(realloc_head, head);
		reassign_resources_sorted(realloc_head, head);
	free_list(resource_list, head);
	free_list(pci_dev_resource, head);
}
}


static void pdev_assign_resources_sorted(struct pci_dev *dev,
static void pdev_assign_resources_sorted(struct pci_dev *dev,
				 struct resource_list_x *add_head,
				 struct list_head *add_head,
				 struct resource_list_x *fail_head)
				 struct list_head *fail_head)
{
{
	struct resource_list head;
	LIST_HEAD(head);


	head.next = NULL;
	__dev_sort_resources(dev, &head);
	__dev_sort_resources(dev, &head);
	__assign_resources_sorted(&head, add_head, fail_head);
	__assign_resources_sorted(&head, add_head, fail_head);


}
}


static void pbus_assign_resources_sorted(const struct pci_bus *bus,
static void pbus_assign_resources_sorted(const struct pci_bus *bus,
					 struct resource_list_x *realloc_head,
					 struct list_head *realloc_head,
					 struct resource_list_x *fail_head)
					 struct list_head *fail_head)
{
{
	struct pci_dev *dev;
	struct pci_dev *dev;
	struct resource_list head;
	LIST_HEAD(head);


	head.next = NULL;
	list_for_each_entry(dev, &bus->devices, bus_list)
	list_for_each_entry(dev, &bus->devices, bus_list)
		__dev_sort_resources(dev, &head);
		__dev_sort_resources(dev, &head);


@@ -713,7 +714,7 @@ static resource_size_t calculate_memsize(resource_size_t size,
 * We must be careful with the ISA aliasing though.
 * We must be careful with the ISA aliasing though.
 */
 */
static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
		resource_size_t add_size, struct resource_list_x *realloc_head)
		resource_size_t add_size, struct list_head *realloc_head)
{
{
	struct pci_dev *dev;
	struct pci_dev *dev;
	struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
	struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO);
@@ -781,7 +782,7 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
			 unsigned long type, resource_size_t min_size,
			 unsigned long type, resource_size_t min_size,
			resource_size_t add_size,
			resource_size_t add_size,
			struct resource_list_x *realloc_head)
			struct list_head *realloc_head)
{
{
	struct pci_dev *dev;
	struct pci_dev *dev;
	resource_size_t min_align, align, size, size0, size1;
	resource_size_t min_align, align, size, size0, size1;
@@ -891,7 +892,7 @@ unsigned long pci_cardbus_resource_alignment(struct resource *res)
}
}


static void pci_bus_size_cardbus(struct pci_bus *bus,
static void pci_bus_size_cardbus(struct pci_bus *bus,
			struct resource_list_x *realloc_head)
			struct list_head *realloc_head)
{
{
	struct pci_dev *bridge = bus->self;
	struct pci_dev *bridge = bus->self;
	struct resource *b_res = &bridge->resource[PCI_BRIDGE_RESOURCES];
	struct resource *b_res = &bridge->resource[PCI_BRIDGE_RESOURCES];
@@ -953,7 +954,7 @@ static void pci_bus_size_cardbus(struct pci_bus *bus,
}
}


void __ref __pci_bus_size_bridges(struct pci_bus *bus,
void __ref __pci_bus_size_bridges(struct pci_bus *bus,
			struct resource_list_x *realloc_head)
			struct list_head *realloc_head)
{
{
	struct pci_dev *dev;
	struct pci_dev *dev;
	unsigned long mask, prefmask;
	unsigned long mask, prefmask;
@@ -1024,8 +1025,8 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus)
EXPORT_SYMBOL(pci_bus_size_bridges);
EXPORT_SYMBOL(pci_bus_size_bridges);


static void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
static void __ref __pci_bus_assign_resources(const struct pci_bus *bus,
					 struct resource_list_x *realloc_head,
					 struct list_head *realloc_head,
					 struct resource_list_x *fail_head)
					 struct list_head *fail_head)
{
{
	struct pci_bus *b;
	struct pci_bus *b;
	struct pci_dev *dev;
	struct pci_dev *dev;
@@ -1064,8 +1065,8 @@ void __ref pci_bus_assign_resources(const struct pci_bus *bus)
EXPORT_SYMBOL(pci_bus_assign_resources);
EXPORT_SYMBOL(pci_bus_assign_resources);


static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge,
static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge,
					 struct resource_list_x *add_head,
					 struct list_head *add_head,
					 struct resource_list_x *fail_head)
					 struct list_head *fail_head)
{
{
	struct pci_bus *b;
	struct pci_bus *b;


@@ -1249,20 +1250,18 @@ void __init
pci_assign_unassigned_resources(void)
pci_assign_unassigned_resources(void)
{
{
	struct pci_bus *bus;
	struct pci_bus *bus;
	struct resource_list_x realloc_list; /* list of resources that
	LIST_HEAD(realloc_head); /* list of resources that
					want additional resources */
					want additional resources */
	struct resource_list_x *add_list = NULL;
	struct list_head *add_list = NULL;
	int tried_times = 0;
	int tried_times = 0;
	enum release_type rel_type = leaf_only;
	enum release_type rel_type = leaf_only;
	struct resource_list_x head, *list;
	LIST_HEAD(fail_head);
	struct pci_dev_resource_x *dev_res_x;
	unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
	unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
				  IORESOURCE_PREFETCH;
				  IORESOURCE_PREFETCH;
	unsigned long failed_type;
	unsigned long failed_type;
	int pci_try_num = 1;
	int pci_try_num = 1;


	head.next = NULL;
	realloc_list.next = NULL;

	/* don't realloc if asked to do so */
	/* don't realloc if asked to do so */
	if (pci_realloc_enabled()) {
	if (pci_realloc_enabled()) {
		int max_depth = pci_get_max_depth();
		int max_depth = pci_get_max_depth();
@@ -1278,7 +1277,7 @@ pci_assign_unassigned_resources(void)
	 * must have, so can realloc parent bridge resource
	 * must have, so can realloc parent bridge resource
	 */
	 */
	if (tried_times + 1 == pci_try_num)
	if (tried_times + 1 == pci_try_num)
		add_list = &realloc_list;
		add_list = &realloc_head;
	/* Depth first, calculate sizes and alignments of all
	/* Depth first, calculate sizes and alignments of all
	   subordinate buses. */
	   subordinate buses. */
	list_for_each_entry(bus, &pci_root_buses, node)
	list_for_each_entry(bus, &pci_root_buses, node)
@@ -1286,27 +1285,26 @@ pci_assign_unassigned_resources(void)


	/* Depth last, allocate resources and update the hardware. */
	/* Depth last, allocate resources and update the hardware. */
	list_for_each_entry(bus, &pci_root_buses, node)
	list_for_each_entry(bus, &pci_root_buses, node)
		__pci_bus_assign_resources(bus, add_list, &head);
		__pci_bus_assign_resources(bus, add_list, &fail_head);
	if (add_list)
	if (add_list)
		BUG_ON(add_list->next);
		BUG_ON(!list_empty(add_list));
	tried_times++;
	tried_times++;


	/* any device complain? */
	/* any device complain? */
	if (!head.next)
	if (list_empty(&fail_head))
		goto enable_and_dump;
		goto enable_and_dump;


	failed_type = 0;
	failed_type = 0;
	for (list = head.next; list;) {
	list_for_each_entry(dev_res_x, &fail_head, list)
		failed_type |= list->flags;
		failed_type |= dev_res_x->flags;
		list = list->next;

	}
	/*
	/*
	 * io port are tight, don't try extra
	 * io port are tight, don't try extra
	 * or if reach the limit, don't want to try more
	 * or if reach the limit, don't want to try more
	 */
	 */
	failed_type &= type_mask;
	failed_type &= type_mask;
	if ((failed_type == IORESOURCE_IO) || (tried_times >= pci_try_num)) {
	if ((failed_type == IORESOURCE_IO) || (tried_times >= pci_try_num)) {
		free_list(resource_list_x, &head);
		free_list(pci_dev_resource_x, &fail_head);
		goto enable_and_dump;
		goto enable_and_dump;
	}
	}


@@ -1321,25 +1319,23 @@ pci_assign_unassigned_resources(void)
	 * Try to release leaf bridge's resources that doesn't fit resource of
	 * Try to release leaf bridge's resources that doesn't fit resource of
	 * child device under that bridge
	 * child device under that bridge
	 */
	 */
	for (list = head.next; list;) {
	list_for_each_entry(dev_res_x, &fail_head, list) {
		bus = list->dev->bus;
		bus = dev_res_x->dev->bus;
		pci_bus_release_bridge_resources(bus, list->flags & type_mask,
		pci_bus_release_bridge_resources(bus,
						 dev_res_x->flags & type_mask,
						 rel_type);
						 rel_type);
		list = list->next;
	}
	}
	/* restore size and flags */
	/* restore size and flags */
	for (list = head.next; list;) {
	list_for_each_entry(dev_res_x, &fail_head, list) {
		struct resource *res = list->res;
		struct resource *res = dev_res_x->res;


		res->start = list->start;
		res->start = dev_res_x->start;
		res->end = list->end;
		res->end = dev_res_x->end;
		res->flags = list->flags;
		res->flags = dev_res_x->flags;
		if (list->dev->subordinate)
		if (dev_res_x->dev->subordinate)
			res->flags = 0;
			res->flags = 0;

		list = list->next;
	}
	}
	free_list(resource_list_x, &head);
	free_list(pci_dev_resource_x, &fail_head);


	goto again;
	goto again;


@@ -1356,29 +1352,27 @@ pci_assign_unassigned_resources(void)
void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
{
{
	struct pci_bus *parent = bridge->subordinate;
	struct pci_bus *parent = bridge->subordinate;
	struct resource_list_x add_list; /* list of resources that
	LIST_HEAD(add_list); /* list of resources that
					want additional resources */
					want additional resources */
	int tried_times = 0;
	int tried_times = 0;
	struct resource_list_x head, *list;
	LIST_HEAD(fail_head);
	struct pci_dev_resource_x *dev_res_x;
	int retval;
	int retval;
	unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
	unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
				  IORESOURCE_PREFETCH;
				  IORESOURCE_PREFETCH;


	head.next = NULL;
	add_list.next = NULL;

again:
again:
	__pci_bus_size_bridges(parent, &add_list);
	__pci_bus_size_bridges(parent, &add_list);
	__pci_bridge_assign_resources(bridge, &add_list, &head);
	__pci_bridge_assign_resources(bridge, &add_list, &fail_head);
	BUG_ON(add_list.next);
	BUG_ON(!list_empty(&add_list));
	tried_times++;
	tried_times++;


	if (!head.next)
	if (list_empty(&fail_head))
		goto enable_all;
		goto enable_all;


	if (tried_times >= 2) {
	if (tried_times >= 2) {
		/* still fail, don't need to try more */
		/* still fail, don't need to try more */
		free_list(resource_list_x, &head);
		free_list(pci_dev_resource_x, &fail_head);
		goto enable_all;
		goto enable_all;
	}
	}


@@ -1389,27 +1383,24 @@ void pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
	 * Try to release leaf bridge's resources that doesn't fit resource of
	 * Try to release leaf bridge's resources that doesn't fit resource of
	 * child device under that bridge
	 * child device under that bridge
	 */
	 */
	for (list = head.next; list;) {
	list_for_each_entry(dev_res_x, &fail_head, list) {
		struct pci_bus *bus = list->dev->bus;
		struct pci_bus *bus = dev_res_x->dev->bus;
		unsigned long flags = list->flags;
		unsigned long flags = dev_res_x->flags;


		pci_bus_release_bridge_resources(bus, flags & type_mask,
		pci_bus_release_bridge_resources(bus, flags & type_mask,
						 whole_subtree);
						 whole_subtree);
		list = list->next;
	}
	}
	/* restore size and flags */
	/* restore size and flags */
	for (list = head.next; list;) {
	list_for_each_entry(dev_res_x, &fail_head, list) {
		struct resource *res = list->res;
		struct resource *res = dev_res_x->res;


		res->start = list->start;
		res->start = dev_res_x->start;
		res->end = list->end;
		res->end = dev_res_x->end;
		res->flags = list->flags;
		res->flags = dev_res_x->flags;
		if (list->dev->subordinate)
		if (dev_res_x->dev->subordinate)
			res->flags = 0;
			res->flags = 0;

		list = list->next;
	}
	}
	free_list(resource_list_x, &head);
	free_list(pci_dev_resource_x, &fail_head);


	goto again;
	goto again;


@@ -1434,12 +1425,11 @@ unsigned int __ref pci_rescan_bus(struct pci_bus *bus)
{
{
	unsigned int max;
	unsigned int max;
	struct pci_dev *dev;
	struct pci_dev *dev;
	struct resource_list_x add_list; /* list of resources that
	LIST_HEAD(add_list); /* list of resources that
					want additional resources */
					want additional resources */


	max = pci_scan_child_bus(bus);
	max = pci_scan_child_bus(bus);


	add_list.next = NULL;
	down_read(&pci_bus_sem);
	down_read(&pci_bus_sem);
	list_for_each_entry(dev, &bus->devices, bus_list)
	list_for_each_entry(dev, &bus->devices, bus_list)
		if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
		if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE ||
@@ -1449,7 +1439,7 @@ unsigned int __ref pci_rescan_bus(struct pci_bus *bus)
							 &add_list);
							 &add_list);
	up_read(&pci_bus_sem);
	up_read(&pci_bus_sem);
	__pci_bus_assign_resources(bus, &add_list, NULL);
	__pci_bus_assign_resources(bus, &add_list, NULL);
	BUG_ON(add_list.next);
	BUG_ON(!list_empty(&add_list));


	pci_enable_bridges(bus);
	pci_enable_bridges(bus);
	pci_bus_add_devices(bus);
	pci_bus_add_devices(bus);