diff options
Diffstat (limited to 'drivers/pci/setup-bus.c')
| -rw-r--r-- | drivers/pci/setup-bus.c | 356 | 
1 files changed, 219 insertions, 137 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index bc26d7990cc..a5a63ecfb62 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -68,7 +68,7 @@ static int add_to_list(struct list_head *head,  	tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);  	if (!tmp) { -		pr_warning("add_to_list: kmalloc() failed!\n"); +		pr_warn("add_to_list: kmalloc() failed!\n");  		return -ENOMEM;  	} @@ -148,8 +148,7 @@ static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head)  		tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);  		if (!tmp) -			panic("pdev_sort_resources(): " -			      "kmalloc() failed!\n"); +			panic("pdev_sort_resources(): kmalloc() failed!\n");  		tmp->res = r;  		tmp->dev = dev; @@ -292,8 +291,8 @@ static void assign_requested_resources_sorted(struct list_head *head,  				      (!(res->flags & IORESOURCE_ROM_ENABLE))))  					add_to_list(fail_head,  						    dev_res->dev, res, -						    0 /* dont care */, -						    0 /* dont care */); +						    0 /* don't care */, +						    0 /* don't care */);  			}  			reset_resource(res);  		} @@ -475,7 +474,7 @@ void pci_setup_cardbus(struct pci_bus *bus)  		 &bus->busn_res);  	res = bus->resource[0]; -	pcibios_resource_to_bus(bridge, ®ion, res); +	pcibios_resource_to_bus(bridge->bus, ®ion, res);  	if (res->flags & IORESOURCE_IO) {  		/*  		 * The IO resource is allocated a range twice as large as it @@ -489,7 +488,7 @@ void pci_setup_cardbus(struct pci_bus *bus)  	}  	res = bus->resource[1]; -	pcibios_resource_to_bus(bridge, ®ion, res); +	pcibios_resource_to_bus(bridge->bus, ®ion, res);  	if (res->flags & IORESOURCE_IO) {  		dev_info(&bridge->dev, "  bridge window %pR\n", res);  		pci_write_config_dword(bridge, PCI_CB_IO_BASE_1, @@ -499,7 +498,7 @@ void pci_setup_cardbus(struct pci_bus *bus)  	}  	res = bus->resource[2]; -	pcibios_resource_to_bus(bridge, ®ion, res); +	pcibios_resource_to_bus(bridge->bus, ®ion, res);  	if (res->flags & IORESOURCE_MEM) {  		dev_info(&bridge->dev, "  bridge window %pR\n", res);  		pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0, @@ -509,7 +508,7 @@ void pci_setup_cardbus(struct pci_bus *bus)  	}  	res = bus->resource[3]; -	pcibios_resource_to_bus(bridge, ®ion, res); +	pcibios_resource_to_bus(bridge->bus, ®ion, res);  	if (res->flags & IORESOURCE_MEM) {  		dev_info(&bridge->dev, "  bridge window %pR\n", res);  		pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1, @@ -538,7 +537,8 @@ static void pci_setup_bridge_io(struct pci_bus *bus)  	struct pci_bus_region region;  	unsigned long io_mask;  	u8 io_base_lo, io_limit_lo; -	u32 l, io_upper16; +	u16 l; +	u32 io_upper16;  	io_mask = PCI_IO_RANGE_MASK;  	if (bridge->io_window_1k) @@ -546,13 +546,12 @@ static void pci_setup_bridge_io(struct pci_bus *bus)  	/* Set up the top and bottom of the PCI I/O segment for this bus. */  	res = bus->resource[0]; -	pcibios_resource_to_bus(bridge, ®ion, res); +	pcibios_resource_to_bus(bridge->bus, ®ion, res);  	if (res->flags & IORESOURCE_IO) { -		pci_read_config_dword(bridge, PCI_IO_BASE, &l); -		l &= 0xffff0000; +		pci_read_config_word(bridge, PCI_IO_BASE, &l);  		io_base_lo = (region.start >> 8) & io_mask;  		io_limit_lo = (region.end >> 8) & io_mask; -		l |= ((u32) io_limit_lo << 8) | io_base_lo; +		l = ((u16) io_limit_lo << 8) | io_base_lo;  		/* Set up upper 16 bits of I/O base/limit. */  		io_upper16 = (region.end & 0xffff0000) | (region.start >> 16);  		dev_info(&bridge->dev, "  bridge window %pR\n", res); @@ -564,7 +563,7 @@ static void pci_setup_bridge_io(struct pci_bus *bus)  	/* Temporarily disable the I/O range before updating PCI_IO_BASE. */  	pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff);  	/* Update lower 16 bits of I/O base/limit. */ -	pci_write_config_dword(bridge, PCI_IO_BASE, l); +	pci_write_config_word(bridge, PCI_IO_BASE, l);  	/* Update upper 16 bits of I/O base/limit. */  	pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16);  } @@ -578,7 +577,7 @@ static void pci_setup_bridge_mmio(struct pci_bus *bus)  	/* Set up the top and bottom of the PCI Memory segment for this bus. */  	res = bus->resource[1]; -	pcibios_resource_to_bus(bridge, ®ion, res); +	pcibios_resource_to_bus(bridge->bus, ®ion, res);  	if (res->flags & IORESOURCE_MEM) {  		l = (region.start >> 16) & 0xfff0;  		l |= region.end & 0xfff00000; @@ -604,7 +603,7 @@ static void pci_setup_bridge_mmio_pref(struct pci_bus *bus)  	/* Set up PREF base/limit. */  	bu = lu = 0;  	res = bus->resource[2]; -	pcibios_resource_to_bus(bridge, ®ion, res); +	pcibios_resource_to_bus(bridge->bus, ®ion, res);  	if (res->flags & IORESOURCE_PREFETCH) {  		l = (region.start >> 16) & 0xfff0;  		l |= region.end & 0xfff00000; @@ -665,21 +664,23 @@ static void pci_bridge_check_ranges(struct pci_bus *bus)  	pci_read_config_word(bridge, PCI_IO_BASE, &io);  	if (!io) { -		pci_write_config_word(bridge, PCI_IO_BASE, 0xf0f0); +		pci_write_config_word(bridge, PCI_IO_BASE, 0xe0f0);  		pci_read_config_word(bridge, PCI_IO_BASE, &io); - 		pci_write_config_word(bridge, PCI_IO_BASE, 0x0); - 	} - 	if (io) +		pci_write_config_word(bridge, PCI_IO_BASE, 0x0); +	} +	if (io)  		b_res[0].flags |= IORESOURCE_IO; +  	/*  DECchip 21050 pass 2 errata: the bridge may miss an address  	    disconnect boundary by one PCI data phase.  	    Workaround: do not use prefetching on this device. */  	if (bridge->vendor == PCI_VENDOR_ID_DEC && bridge->device == 0x0001)  		return; +  	pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);  	if (!pmem) {  		pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, -					       0xfff0fff0); +					       0xffe0fff0);  		pci_read_config_dword(bridge, PCI_PREF_MEMORY_BASE, &pmem);  		pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, 0x0);  	} @@ -711,12 +712,11 @@ static void pci_bridge_check_ranges(struct pci_bus *bus)     bus resource of a given type. Note: we intentionally skip     the bus resources which have already been assigned (that is,     have non-NULL parent resource). */ -static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned long type) +static struct resource *find_free_bus_resource(struct pci_bus *bus, +			 unsigned long type_mask, unsigned long type)  {  	int i;  	struct resource *r; -	unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | -				  IORESOURCE_PREFETCH;  	pci_bus_for_each_resource(bus, r, i) {  		if (r == &ioport_resource || r == &iomem_resource) @@ -735,7 +735,7 @@ static resource_size_t calculate_iosize(resource_size_t size,  {  	if (size < min_size)  		size = min_size; -	if (old_size == 1 ) +	if (old_size == 1)  		old_size = 0;  	/* To be fixed in 2.5: we should have sort of HAVE_ISA  	   flag in the struct pci_bus. */ @@ -756,7 +756,7 @@ static resource_size_t calculate_memsize(resource_size_t size,  {  	if (size < min_size)  		size = min_size; -	if (old_size == 1 ) +	if (old_size == 1)  		old_size = 0;  	if (size < old_size)  		size = old_size; @@ -813,13 +813,14 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,  		resource_size_t add_size, struct list_head *realloc_head)  {  	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, +							IORESOURCE_IO);  	resource_size_t size = 0, size0 = 0, size1 = 0;  	resource_size_t children_add_size = 0;  	resource_size_t min_align, align;  	if (!b_res) - 		return; +		return;  	min_align = window_alignment(bus, IORESOURCE_IO);  	list_for_each_entry(dev, &bus->devices, bus_list) { @@ -857,9 +858,8 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,  			resource_size(b_res), min_align);  	if (!size0 && !size1) {  		if (b_res->start || b_res->end) -			dev_info(&bus->self->dev, "disabling bridge window " -				 "%pR to %pR (unused)\n", b_res, -				 &bus->busn_res); +			dev_info(&bus->self->dev, "disabling bridge window %pR to %pR (unused)\n", +				 b_res, &bus->busn_res);  		b_res->flags = 0;  		return;  	} @@ -870,10 +870,9 @@ static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,  	if (size1 > size0 && realloc_head) {  		add_to_list(realloc_head, bus->self, b_res, size1-size0,  			    min_align); -		dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window " -				 "%pR to %pR add_size %llx\n", b_res, -				 &bus->busn_res, -				 (unsigned long long)size1-size0); +		dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window %pR to %pR add_size %llx\n", +			   b_res, &bus->busn_res, +			   (unsigned long long)size1-size0);  	}  } @@ -905,36 +904,40 @@ static inline resource_size_t calculate_mem_align(resource_size_t *aligns,   * @bus : the bus   * @mask: mask the resource flag, then compare it with type   * @type: the type of free resource from bridge + * @type2: second match type + * @type3: third match type   * @min_size : the minimum memory window that must to be allocated   * @add_size : additional optional memory window   * @realloc_head : track the additional memory window on this list   *   * Calculate the size of the bus and minimal alignment which   * guarantees that all child resources fit in this size. + * + * Returns -ENOSPC if there's no available bus resource of the desired type. + * Otherwise, sets the bus resource start/end to indicate the required + * size, adds things to realloc_head (if supplied), and returns 0.   */  static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, -			 unsigned long type, resource_size_t min_size, -			resource_size_t add_size, -			struct list_head *realloc_head) +			 unsigned long type, unsigned long type2, +			 unsigned long type3, +			 resource_size_t min_size, resource_size_t add_size, +			 struct list_head *realloc_head)  {  	struct pci_dev *dev;  	resource_size_t min_align, align, size, size0, size1; -	resource_size_t aligns[12];	/* Alignments from 1Mb to 2Gb */ +	resource_size_t aligns[14];	/* Alignments from 1Mb to 8Gb */  	int order, max_order; -	struct resource *b_res = find_free_bus_resource(bus, type); -	unsigned int mem64_mask = 0; +	struct resource *b_res = find_free_bus_resource(bus, +					mask | IORESOURCE_PREFETCH, type);  	resource_size_t children_add_size = 0;  	if (!b_res) -		return 0; +		return -ENOSPC;  	memset(aligns, 0, sizeof(aligns));  	max_order = 0;  	size = 0; -	mem64_mask = b_res->flags & IORESOURCE_MEM_64; -	b_res->flags &= ~IORESOURCE_MEM_64; -  	list_for_each_entry(dev, &bus->devices, bus_list) {  		int i; @@ -942,7 +945,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,  			struct resource *r = &dev->resource[i];  			resource_size_t r_size; -			if (r->parent || (r->flags & mask) != type) +			if (r->parent || ((r->flags & mask) != type && +					  (r->flags & mask) != type2 && +					  (r->flags & mask) != type3))  				continue;  			r_size = resource_size(r);  #ifdef CONFIG_PCI_IOV @@ -950,31 +955,34 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,  			if (realloc_head && i >= PCI_IOV_RESOURCES &&  					i <= PCI_IOV_RESOURCE_END) {  				r->end = r->start - 1; -				add_to_list(realloc_head, dev, r, r_size, 0/* dont' care */); +				add_to_list(realloc_head, dev, r, r_size, 0/* don't care */);  				children_add_size += r_size;  				continue;  			}  #endif -			/* For bridges size != alignment */ +			/* +			 * aligns[0] is for 1MB (since bridge memory +			 * windows are always at least 1MB aligned), so +			 * keep "order" from being negative for smaller +			 * resources. +			 */  			align = pci_resource_alignment(dev, r);  			order = __ffs(align) - 20; -			if (order > 11) { -				dev_warn(&dev->dev, "disabling BAR %d: %pR " -					 "(bad alignment %#llx)\n", i, r, -					 (unsigned long long) align); +			if (order < 0) +				order = 0; +			if (order >= ARRAY_SIZE(aligns)) { +				dev_warn(&dev->dev, "disabling BAR %d: %pR (bad alignment %#llx)\n", +					 i, r, (unsigned long long) align);  				r->flags = 0;  				continue;  			}  			size += r_size; -			if (order < 0) -				order = 0;  			/* Exclude ranges with size > align from  			   calculation of the alignment. */  			if (r_size == align)  				aligns[order] += align;  			if (order > max_order)  				max_order = order; -			mem64_mask &= r->flags & IORESOURCE_MEM_64;  			if (realloc_head)  				children_add_size += get_res_add_size(realloc_head, r); @@ -982,7 +990,7 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,  	}  	min_align = calculate_mem_align(aligns, max_order); -	min_align = max(min_align, window_alignment(bus, b_res->flags & mask)); +	min_align = max(min_align, window_alignment(bus, b_res->flags));  	size0 = calculate_memsize(size, min_size, 0, resource_size(b_res), min_align);  	if (children_add_size > add_size)  		add_size = children_add_size; @@ -991,22 +999,21 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask,  				resource_size(b_res), min_align);  	if (!size0 && !size1) {  		if (b_res->start || b_res->end) -			dev_info(&bus->self->dev, "disabling bridge window " -				 "%pR to %pR (unused)\n", b_res, -				 &bus->busn_res); +			dev_info(&bus->self->dev, "disabling bridge window %pR to %pR (unused)\n", +				 b_res, &bus->busn_res);  		b_res->flags = 0; -		return 1; +		return 0;  	}  	b_res->start = min_align;  	b_res->end = size0 + min_align - 1; -	b_res->flags |= IORESOURCE_STARTALIGN | mem64_mask; +	b_res->flags |= IORESOURCE_STARTALIGN;  	if (size1 > size0 && realloc_head) {  		add_to_list(realloc_head, bus->self, b_res, size1-size0, min_align); -		dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window " -				 "%pR to %pR add_size %llx\n", b_res, -				 &bus->busn_res, (unsigned long long)size1-size0); +		dev_printk(KERN_DEBUG, &bus->self->dev, "bridge window %pR to %pR add_size %llx\n", +			   b_res, &bus->busn_res, +			   (unsigned long long)size1-size0);  	} -	return 1; +	return 0;  }  unsigned long pci_cardbus_resource_alignment(struct resource *res) @@ -1111,12 +1118,13 @@ handle_done:  	;  } -void __ref __pci_bus_size_bridges(struct pci_bus *bus, -			struct list_head *realloc_head) +void __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)  {  	struct pci_dev *dev; -	unsigned long mask, prefmask; +	unsigned long mask, prefmask, type2 = 0, type3 = 0;  	resource_size_t additional_mem_size = 0, additional_io_size = 0; +	struct resource *b_res; +	int ret;  	list_for_each_entry(dev, &bus->devices, bus_list) {  		struct pci_bus *b = dev->subordinate; @@ -1136,7 +1144,7 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,  	}  	/* The root bus? */ -	if (!bus->self) +	if (pci_is_root_bus(bus))  		return;  	switch (bus->self->class >> 8) { @@ -1150,41 +1158,93 @@ void __ref __pci_bus_size_bridges(struct pci_bus *bus,  			additional_io_size  = pci_hotplug_io_size;  			additional_mem_size = pci_hotplug_mem_size;  		} -		/* -		 * Follow thru -		 */ +		/* Fall through */  	default:  		pbus_size_io(bus, realloc_head ? 0 : additional_io_size,  			     additional_io_size, realloc_head); -		/* If the bridge supports prefetchable range, size it -		   separately. If it doesn't, or its prefetchable window -		   has already been allocated by arch code, try -		   non-prefetchable range for both types of PCI memory -		   resources. */ + +		/* +		 * If there's a 64-bit prefetchable MMIO window, compute +		 * the size required to put all 64-bit prefetchable +		 * resources in it. +		 */ +		b_res = &bus->self->resource[PCI_BRIDGE_RESOURCES];  		mask = IORESOURCE_MEM;  		prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH; -		if (pbus_size_mem(bus, prefmask, prefmask, +		if (b_res[2].flags & IORESOURCE_MEM_64) { +			prefmask |= IORESOURCE_MEM_64; +			ret = pbus_size_mem(bus, prefmask, prefmask, +				  prefmask, prefmask,  				  realloc_head ? 0 : additional_mem_size, -				  additional_mem_size, realloc_head)) -			mask = prefmask; /* Success, size non-prefetch only. */ -		else -			additional_mem_size += additional_mem_size; -		pbus_size_mem(bus, mask, IORESOURCE_MEM, +				  additional_mem_size, realloc_head); + +			/* +			 * If successful, all non-prefetchable resources +			 * and any 32-bit prefetchable resources will go in +			 * the non-prefetchable window. +			 */ +			if (ret == 0) { +				mask = prefmask; +				type2 = prefmask & ~IORESOURCE_MEM_64; +				type3 = prefmask & ~IORESOURCE_PREFETCH; +			} +		} + +		/* +		 * If there is no 64-bit prefetchable window, compute the +		 * size required to put all prefetchable resources in the +		 * 32-bit prefetchable window (if there is one). +		 */ +		if (!type2) { +			prefmask &= ~IORESOURCE_MEM_64; +			ret = pbus_size_mem(bus, prefmask, prefmask, +					 prefmask, prefmask, +					 realloc_head ? 0 : additional_mem_size, +					 additional_mem_size, realloc_head); + +			/* +			 * If successful, only non-prefetchable resources +			 * will go in the non-prefetchable window. +			 */ +			if (ret == 0) +				mask = prefmask; +			else +				additional_mem_size += additional_mem_size; + +			type2 = type3 = IORESOURCE_MEM; +		} + +		/* +		 * Compute the size required to put everything else in the +		 * non-prefetchable window.  This includes: +		 * +		 *   - all non-prefetchable resources +		 *   - 32-bit prefetchable resources if there's a 64-bit +		 *     prefetchable window or no prefetchable window at all +		 *   - 64-bit prefetchable resources if there's no +		 *     prefetchable window at all +		 * +		 * Note that the strategy in __pci_assign_resource() must +		 * match that used here.  Specifically, we cannot put a +		 * 32-bit prefetchable resource in a 64-bit prefetchable +		 * window. +		 */ +		pbus_size_mem(bus, mask, IORESOURCE_MEM, type2, type3,  				realloc_head ? 0 : additional_mem_size,  				additional_mem_size, realloc_head);  		break;  	}  } -void __ref pci_bus_size_bridges(struct pci_bus *bus) +void pci_bus_size_bridges(struct pci_bus *bus)  {  	__pci_bus_size_bridges(bus, NULL);  }  EXPORT_SYMBOL(pci_bus_size_bridges); -void __ref __pci_bus_assign_resources(const struct pci_bus *bus, -				      struct list_head *realloc_head, -				      struct list_head *fail_head) +void __pci_bus_assign_resources(const struct pci_bus *bus, +				struct list_head *realloc_head, +				struct list_head *fail_head)  {  	struct pci_bus *b;  	struct pci_dev *dev; @@ -1209,22 +1269,22 @@ void __ref __pci_bus_assign_resources(const struct pci_bus *bus,  			break;  		default: -			dev_info(&dev->dev, "not setting up bridge for bus " -				 "%04x:%02x\n", pci_domain_nr(b), b->number); +			dev_info(&dev->dev, "not setting up bridge for bus %04x:%02x\n", +				 pci_domain_nr(b), b->number);  			break;  		}  	}  } -void __ref pci_bus_assign_resources(const struct pci_bus *bus) +void pci_bus_assign_resources(const struct pci_bus *bus)  {  	__pci_bus_assign_resources(bus, NULL, NULL);  }  EXPORT_SYMBOL(pci_bus_assign_resources); -static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge, -					 struct list_head *add_head, -					 struct list_head *fail_head) +static void __pci_bridge_assign_resources(const struct pci_dev *bridge, +					  struct list_head *add_head, +					  struct list_head *fail_head)  {  	struct pci_bus *b; @@ -1247,50 +1307,74 @@ static void __ref __pci_bridge_assign_resources(const struct pci_dev *bridge,  		break;  	default: -		dev_info(&bridge->dev, "not setting up bridge for bus " -			 "%04x:%02x\n", pci_domain_nr(b), b->number); +		dev_info(&bridge->dev, "not setting up bridge for bus %04x:%02x\n", +			 pci_domain_nr(b), b->number);  		break;  	}  }  static void pci_bridge_release_resources(struct pci_bus *bus,  					  unsigned long type)  { -	int idx; -	bool changed = false; -	struct pci_dev *dev; +	struct pci_dev *dev = bus->self;  	struct resource *r;  	unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | -				  IORESOURCE_PREFETCH; +				  IORESOURCE_PREFETCH | IORESOURCE_MEM_64; +	unsigned old_flags = 0; +	struct resource *b_res; +	int idx = 1; -	dev = bus->self; -	for (idx = PCI_BRIDGE_RESOURCES; idx <= PCI_BRIDGE_RESOURCE_END; -	     idx++) { -		r = &dev->resource[idx]; -		if ((r->flags & type_mask) != type) -			continue; -		if (!r->parent) -			continue; -		/* -		 * if there are children under that, we should release them -		 *  all -		 */ -		release_child_resources(r); -		if (!release_resource(r)) { -			dev_printk(KERN_DEBUG, &dev->dev, -				 "resource %d %pR released\n", idx, r); -			/* keep the old size */ -			r->end = resource_size(r) - 1; -			r->start = 0; -			r->flags = 0; -			changed = true; -		} -	} +	b_res = &dev->resource[PCI_BRIDGE_RESOURCES]; + +	/* +	 *     1. if there is io port assign fail, will release bridge +	 *	  io port. +	 *     2. if there is non pref mmio assign fail, release bridge +	 *	  nonpref mmio. +	 *     3. if there is 64bit pref mmio assign fail, and bridge pref +	 *	  is 64bit, release bridge pref mmio. +	 *     4. if there is pref mmio assign fail, and bridge pref is +	 *	  32bit mmio, release bridge pref mmio +	 *     5. if there is pref mmio assign fail, and bridge pref is not +	 *	  assigned, release bridge nonpref mmio. +	 */ +	if (type & IORESOURCE_IO) +		idx = 0; +	else if (!(type & IORESOURCE_PREFETCH)) +		idx = 1; +	else if ((type & IORESOURCE_MEM_64) && +		 (b_res[2].flags & IORESOURCE_MEM_64)) +		idx = 2; +	else if (!(b_res[2].flags & IORESOURCE_MEM_64) && +		 (b_res[2].flags & IORESOURCE_PREFETCH)) +		idx = 2; +	else +		idx = 1; + +	r = &b_res[idx]; + +	if (!r->parent) +		return; + +	/* +	 * if there are children under that, we should release them +	 *  all +	 */ +	release_child_resources(r); +	if (!release_resource(r)) { +		type = old_flags = r->flags & type_mask; +		dev_printk(KERN_DEBUG, &dev->dev, "resource %d %pR released\n", +					PCI_BRIDGE_RESOURCES + idx, r); +		/* keep the old size */ +		r->end = resource_size(r) - 1; +		r->start = 0; +		r->flags = 0; -	if (changed) {  		/* avoiding touch the one without PREF */  		if (type & IORESOURCE_PREFETCH)  			type = IORESOURCE_PREFETCH;  		__pci_setup_bridge(bus, type); +		/* for next child res under same bridge */ +		r->flags = old_flags;  	}  } @@ -1302,9 +1386,9 @@ enum release_type {   * try to release pci bridge resources that is from leaf bridge,   * so we can allocate big new one later   */ -static void __ref pci_bus_release_bridge_resources(struct pci_bus *bus, -						   unsigned long type, -						   enum release_type rel_type) +static void pci_bus_release_bridge_resources(struct pci_bus *bus, +					     unsigned long type, +					     enum release_type rel_type)  {  	struct pci_dev *dev;  	bool is_leaf_bridge = true; @@ -1341,10 +1425,10 @@ static void pci_bus_dump_res(struct pci_bus *bus)  	pci_bus_for_each_resource(bus, res, i) {  		if (!res || !res->end || !res->flags) -                        continue; +			continue;  		dev_printk(KERN_DEBUG, &bus->dev, "resource %d %pR\n", i, res); -        } +	}  }  static void pci_bus_dump_resources(struct pci_bus *bus) @@ -1369,7 +1453,7 @@ static int pci_bus_get_depth(struct pci_bus *bus)  	int depth = 0;  	struct pci_bus *child_bus; -	list_for_each_entry(child_bus, &bus->children, node){ +	list_for_each_entry(child_bus, &bus->children, node) {  		int ret;  		ret = pci_bus_get_depth(child_bus); @@ -1422,7 +1506,7 @@ static int iov_resources_unassigned(struct pci_dev *dev, void *data)  		if (!r->flags)  			continue; -		pcibios_resource_to_bus(dev, ®ion, r); +		pcibios_resource_to_bus(dev->bus, ®ion, r);  		if (!region.start) {  			*unassigned = true;  			return 1; /* return early from pci_walk_bus() */ @@ -1456,8 +1540,8 @@ static enum enable_type pci_realloc_detect(struct pci_bus *bus,  /*   * first try will not touch pci bridge res - * second  and later try will clear small leaf bridge res - * will stop till to the max  deepth if can not find good one + * second and later try will clear small leaf bridge res + * will stop till to the max depth if can not find good one   */  void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus)  { @@ -1469,7 +1553,7 @@ void pci_assign_unassigned_root_bus_resources(struct pci_bus *bus)  	LIST_HEAD(fail_head);  	struct pci_dev_resource *fail_res;  	unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM | -				  IORESOURCE_PREFETCH; +				  IORESOURCE_PREFETCH | IORESOURCE_MEM_64;  	int pci_try_num = 1;  	enum enable_type enable_local; @@ -1627,9 +1711,7 @@ void pci_assign_unassigned_bus_resources(struct pci_bus *bus)  	down_read(&pci_bus_sem);  	list_for_each_entry(dev, &bus->devices, bus_list) -		if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || -		    dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) -			if (dev->subordinate) +		if (pci_is_bridge(dev) && pci_has_subordinate(dev))  				__pci_bus_size_bridges(dev->subordinate,  							 &add_list);  	up_read(&pci_bus_sem);  | 
