mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	PCI: Remove pci_find_parent_resource() use for allocation
If the resource hasn't been allocated yet, pci_find_parent_resource() is
documented as returning the region "where it should be allocated from."
This is impossible in general because there may be several candidates: a
prefetchable BAR can be put in either a prefetchable or non-prefetchable
window, a transparent bridge may have overlapping positively- and
subtractively-decoded windows, and a root bus may have several windows of
the same type.
Allocation should be done by pci_bus_alloc_resource(), which iterates
through all bus resources and looks for the best match, e.g., one with the
desired prefetchability attributes, and falls back to less-desired
possibilities.
The only valid use of pci_find_parent_resource() is to find the parent of
an already-allocated resource so we can claim it via request_resource(),
and all we need for that is a bus region of the correct type that contains
the resource.
Note that like 8c8def26bf ("PCI: allow matching of prefetchable resources
to non-prefetchable windows"), this depends on pci_bus_for_each_resource()
iterating through positively-decoded regions before subtractively-decoded
ones.  We prefer not to return a subtractively-decoded region because
requesting from it will likely conflict with the overlapping positively-
decoded window (see Launchpad report below).
Link: https://bugs.launchpad.net/ubuntu/+source/linux/+bug/424142
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
CC: Linus Torvalds <torvalds@linux-foundation.org>
			
			
This commit is contained in:
		
							parent
							
								
									d19cb803a2
								
							
						
					
					
						commit
						f44116ae88
					
				
					 1 changed files with 23 additions and 16 deletions
				
			
		| 
						 | 
				
			
			@ -401,33 +401,40 @@ EXPORT_SYMBOL_GPL(pci_find_ht_capability);
 | 
			
		|||
 * @res: child resource record for which parent is sought
 | 
			
		||||
 *
 | 
			
		||||
 *  For given resource region of given device, return the resource
 | 
			
		||||
 *  region of parent bus the given region is contained in or where
 | 
			
		||||
 *  it should be allocated from.
 | 
			
		||||
 *  region of parent bus the given region is contained in.
 | 
			
		||||
 */
 | 
			
		||||
struct resource *
 | 
			
		||||
pci_find_parent_resource(const struct pci_dev *dev, struct resource *res)
 | 
			
		||||
{
 | 
			
		||||
	const struct pci_bus *bus = dev->bus;
 | 
			
		||||
	struct resource *r;
 | 
			
		||||
	int i;
 | 
			
		||||
	struct resource *best = NULL, *r;
 | 
			
		||||
 | 
			
		||||
	pci_bus_for_each_resource(bus, r, i) {
 | 
			
		||||
		if (!r)
 | 
			
		||||
			continue;
 | 
			
		||||
		if (res->start && !(res->start >= r->start && res->end <= r->end))
 | 
			
		||||
			continue;	/* Not contained */
 | 
			
		||||
		if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM))
 | 
			
		||||
			continue;	/* Wrong type */
 | 
			
		||||
		if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH))
 | 
			
		||||
			return r;	/* Exact match */
 | 
			
		||||
		/* We can't insert a non-prefetch resource inside a prefetchable parent .. */
 | 
			
		||||
		if (r->flags & IORESOURCE_PREFETCH)
 | 
			
		||||
			continue;
 | 
			
		||||
		/* .. but we can put a prefetchable resource inside a non-prefetchable one */
 | 
			
		||||
		if (!best)
 | 
			
		||||
			best = r;
 | 
			
		||||
		if (res->start && resource_contains(r, res)) {
 | 
			
		||||
 | 
			
		||||
			/*
 | 
			
		||||
			 * If the window is prefetchable but the BAR is
 | 
			
		||||
			 * not, the allocator made a mistake.
 | 
			
		||||
			 */
 | 
			
		||||
			if (r->flags & IORESOURCE_PREFETCH &&
 | 
			
		||||
			    !(res->flags & IORESOURCE_PREFETCH))
 | 
			
		||||
				return NULL;
 | 
			
		||||
 | 
			
		||||
			/*
 | 
			
		||||
			 * If we're below a transparent bridge, there may
 | 
			
		||||
			 * be both a positively-decoded aperture and a
 | 
			
		||||
			 * subtractively-decoded region that contain the BAR.
 | 
			
		||||
			 * We want the positively-decoded one, so this depends
 | 
			
		||||
			 * on pci_bus_for_each_resource() giving us those
 | 
			
		||||
			 * first.
 | 
			
		||||
			 */
 | 
			
		||||
			return r;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return best;
 | 
			
		||||
	return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue