Re: [PATCH] pci: only release that resource index is less than 3

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Mon, 2009-10-26 at 14:23 -0700, Yinghai Lu wrote:

> ===================================================================
> --- linux-2.6.orig/drivers/pci/setup-bus.c
> +++ linux-2.6/drivers/pci/setup-bus.c
> @@ -322,33 +322,54 @@ static void pci_bridge_check_ranges(stru
>  	}
>  }
>  
> -/* Helper function for sizing routines: find first available
> -   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)
> +void pci_bridge_release_not_used_res(struct pci_bus *bus)
>  {
>  	int i;
>  	struct resource *r;
>  	unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
>  				  IORESOURCE_PREFETCH;
>  
> -	for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
> +	/* for pci bridges res only */
> +	for (i = 0; i < 3; i++) {

I think the "i = 0; i < 3" part is to check the bridge apertures, i.e.,
the I/O base/limit, the memory base/limit, and the prefetchable memory
base/limit.  Right?  We need some way to indicate that more clearly than
using a hard-coded "3".

>  		r = bus->resource[i];
> -		if (r == &ioport_resource || r == &iomem_resource)
> -			continue;
> -		if (r && (r->flags & type_mask) == type) {
> +		if (r && (r->flags & type_mask)) {
>  			if (!r->parent)
> -				return r;
> +				continue;
>  			/*
>  			 * if there is no child under that, we should release
>  			 * and use it. don't need to reset it, pbus_size_* will
>  			 * set it again
>  			 */
>  			if (!r->child && !release_resource(r))

We got this resource pointer out of a struct pci_bus, and we release it
here.  We must have previously done a request_resource(),
allocate_resource(), or similar.  Where does that happen?  Are the
requests and releases nested correctly?

I would think that somewhere, we would be doing a request_resource() and
assigning the resource to pci_bus->resource[x].  But there are very few
assignments to the pci_bus resources:
  setup_resource (only for "pci=use_crs")
  pci_read_bridge_bases (just a copy from upstream bus resources)
  pci_alloc_child_bus (copy from upstream bridge resources)
  pci_create_bus (set to &ioport_resource or &iomem_resource)

My guess is that this release_resource() releases something we copied
from the bridge in pci_alloc_child_bus().  But that doesn't seem right,
because we aren't changing the bridge programming here.

Maybe I'm being confused by the fact that we find the resource pointer
from the pci_bus table, but that's only a pointer to the actual struct
resource that lives in the pci_dev of the upstream bridge.

Bjorn

> -				return r;
> +				dev_printk(KERN_DEBUG, &bus->dev,
> +					   "resource %d %s %pR released\n", i,
> +					   (r->flags & IORESOURCE_IO) ? "io: " :
> +					    ((r->flags & IORESOURCE_PREFETCH)?
> +						 "pref mem":"mem:"),
> +					   r);
>  		}
>  	}
> +}
> +EXPORT_SYMBOL(pci_bridge_release_not_used_res);
> +
> +/* Helper function for sizing routines: find first available
> +   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)
> +{
> +	int i;
> +	struct resource *r;
> +	unsigned long type_mask = IORESOURCE_IO | IORESOURCE_MEM |
> +				  IORESOURCE_PREFETCH;
> +
> +	for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
> +		r = bus->resource[i];
> +		if (r == &ioport_resource || r == &iomem_resource)
> +			continue;
> +		if (r && (r->flags & type_mask) == type && !r->parent)
> +			return r;
> +	}
>  	return NULL;
>  }
>  
> @@ -588,6 +609,41 @@ void __ref pci_bus_size_bridges(struct p
>  }
>  EXPORT_SYMBOL(pci_bus_size_bridges);
>  
> +static void pci_bus_release_bridges_not_used_res(struct pci_bus *bus)
> +{
> +	struct pci_dev *dev;
> +
> +	list_for_each_entry(dev, &bus->devices, bus_list) {
> +		struct pci_bus *b = dev->subordinate;
> +		if (!b)
> +			continue;
> +
> +		switch (dev->class >> 8) {
> +		case PCI_CLASS_BRIDGE_CARDBUS:
> +			break;
> +
> +		case PCI_CLASS_BRIDGE_PCI:
> +		default:
> +			pci_bus_release_bridges_not_used_res(b);
> +			break;
> +		}
> +	}
> +
> +	/* The root bus? */
> +	if (!bus->self)
> +		return;
> +
> +	switch (bus->self->class >> 8) {
> +	case PCI_CLASS_BRIDGE_CARDBUS:
> +		break;
> +
> +	case PCI_CLASS_BRIDGE_PCI:
> +	default:
> +		pci_bridge_release_not_used_res(bus);
> +		break;
> +	}
> +}
> +
>  void __ref pci_bridge_assign_resources(const struct pci_dev *bridge)
>  {
>  	struct pci_bus *b;
> @@ -687,6 +743,11 @@ pci_assign_unassigned_resources(void)
>  {
>  	struct pci_bus *bus;
>  
> +	/* Try to release bridge resources, that there is not child under it */
> +	list_for_each_entry(bus, &pci_root_buses, node) {
> +		pci_bus_release_bridges_not_used_res(bus);
> +	}
> +
>  	/* Depth first, calculate sizes and alignments of all
>  	   subordinate buses. */
>  	list_for_each_entry(bus, &pci_root_buses, node) {
> Index: linux-2.6/drivers/pci/hotplug/pciehp_pci.c
> ===================================================================
> --- linux-2.6.orig/drivers/pci/hotplug/pciehp_pci.c
> +++ linux-2.6/drivers/pci/hotplug/pciehp_pci.c
> @@ -171,6 +171,7 @@ int pciehp_unconfigure_device(struct slo
>  		}
>  		pci_dev_put(temp);
>  	}
> +	pci_bridge_release_not_used_res(parent);
>  
>  	return rc;
>  }
> Index: linux-2.6/include/linux/pci.h
> ===================================================================
> --- linux-2.6.orig/include/linux/pci.h
> +++ linux-2.6/include/linux/pci.h
> @@ -759,6 +759,7 @@ int pci_vpd_truncate(struct pci_dev *dev
>  void pci_bridge_assign_resources(const struct pci_dev *bridge);
>  void pci_bus_assign_resources(const struct pci_bus *bus);
>  void pci_bus_size_bridges(struct pci_bus *bus);
> +void pci_bridge_release_not_used_res(struct pci_bus *bus);
>  int pci_claim_resource(struct pci_dev *, int);
>  void pci_assign_unassigned_resources(void);
>  void pdev_enable_device(struct pci_dev *);

--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux