merging PCMCIA changes

Andrew Morton akpm at osdl.org
Sat Jun 18 17:55:13 EDT 2005


Dominik Brodowski <linux at dominikbrodowski.net> wrote:
>
> Hi,
> 
> On Sat, Jun 18, 2005 at 11:17:18AM -0700, Andrew Morton wrote:
> > > Also, one other pci-related change very helpful for PCMCIA was in -mm for
> > > quite some time and, to my knowledge, did not cause any problems. It was
> > > titled 
> > > 
> > > gregkh-pci-pci-pci-transparent-bridge-handling-improvements-pci-core.patch
> > > 
> > > and was present until 2.6.12-rc5-mm2. While a different patch intending the
> > > same functionality is in -mm, the related changes to the PCI infrastructure
> > > cause severe headaches (see bug 
> > > http://bugzilla.kernel.org/show_bug.cgi?id=4737 for example, other, similar
> > > reports were posted to lkml.) Therefore I'd suggest to merge the patch
> > > mentioned above at first, and fix up new PCI patches in -mm first.
> > 
> > The patches in -mm are staged after the git trees (mainly because I'm more
> > flexible with rejects and things than people who are stuck using an SCM ;)
> > 
> > So I tend to wait until the bk/scm guys have merged.
> 
> However, with git-pci being broken at the moment, merging git-pci first does
> not make sense. So isn't this a natural exception to your "normal" rule?
> After all, gregkh-pci-pci-pci-transparent-bridge-handling-improvements-pci-core.patch
> proved to do the right thing in -mm for quite some time. Or what am I
> missing?
> 

Yes, a number of people have reported the things in bug 4737.

I'd prefer that we get a patch in place which fixes up Greg's tree instead
of doing something in parallel.

It's up to Greg, really.

Here's the patch:


>From akpm at osdl.org Wed Mar 30 13:29:03 2005
Subject: PCI-PCI transparent bridge handling improvements (pci core)
To: greg at kroah.com
Cc: akpm at osdl.org, linux at dominikbrodowski.net
From: akpm at osdl.org
Date: Wed, 30 Mar 2005 13:23:32 -0800

From: Dominik Brodowski <linux at dominikbrodowski.net>

"Transparent" PCI-PCI bridges are currently "ignored" by the resource
management code in the PCI core.  This means devices behind the bridge are
handled as if there was no bridge.

However, it seems more suitable -- and it seems to allow for proper
"prefetch"-type memory handling, too -- to handle a transparent PCI-PCI
bridge like any other PCI-PCI bridge, and to only break out of the limits
set by the bridge windows if the resource allocation code determines it
needs to do s.

The tricky part is in pci_find_parent_resource().  There are two types of
functions calling it: some functions already know the exact resource for
which they want to find the parent in order to properly insert it into the
resource database.  This can be handled easily -- if the resource is inside
the bridge window, this is returned; if it isn't, the bridge's parent
resource is returned.

However, two callers (yenta_socket and i2o) intend something different:
they call pci_find_parent_resource() with an empty resource and want to
find out the biggest valid resource of the proper type in order to analyze
it and adapt its own hunger for resources to it.  To keep this behaviour
backwards-compatible, we always need to not limit it to the bridge window
resources, but get back to the parent bus.

This patch is a modified and (hopefully) improved derivation of Linus' 
"pcmcia-bridge-resource-management-fix.patch" included in 2.6.11-rc4-mm1.

Signed-off-by: Dominik Brodowski <linux at dominikbrodowski.net>
Signed-off-by: Andrew Morton <akpm at osdl.org>
Signed-off-by: Greg Kroah-Hartman <gregkh at suse.de>

Index: gregkh-2.6/drivers/pci/bus.c
===================================================================
--- gregkh-2.6.orig/drivers/pci/bus.c	2005-04-12 22:36:19.000000000 -0700
+++ gregkh-2.6/drivers/pci/bus.c	2005-04-12 22:38:42.000000000 -0700
@@ -18,22 +18,12 @@
 #include "pci.h"
 
 /**
- * pci_bus_alloc_resource - allocate a resource from a parent bus
- * @bus: PCI bus
- * @res: resource to allocate
- * @size: size of resource to allocate
- * @align: alignment of resource to allocate
- * @min: minimum /proc/iomem address to allocate
- * @type_mask: IORESOURCE_* type flags
- * @alignf: resource alignment function
- * @alignf_data: data argument for resource alignment function
+ * pci_one_bus_alloc_resource - allocate a resource from one specific bus
  *
- * Given the PCI bus a device resides on, the size, minimum address,
- * alignment and type, try to find an acceptable resource allocation
- * for a specific device resource.
+ * Always use pci_bus_alloc_resource() described below.
  */
-int
-pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
+static int
+pci_one_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
 	unsigned long size, unsigned long align, unsigned long min,
 	unsigned int type_mask,
 	void (*alignf)(void *, struct resource *,
@@ -69,6 +59,48 @@
 }
 
 /**
+ * pci_bus_alloc_resource - allocate a resource from a parent bus
+ * @bus: PCI bus
+ * @res: resource to allocate
+ * @size: size of resource to allocate
+ * @align: alignment of resource to allocate
+ * @min: minimum /proc/iomem address to allocate
+ * @type_mask: IORESOURCE_* type flags
+ * @alignf: resource alignment function
+ * @alignf_data: data argument for resource alignment function
+ *
+ * Given the PCI bus a device resides on, the size, minimum address,
+ * alignment and type, try to find an acceptable resource allocation
+ * for a specific device resource.
+ */
+int
+pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res,
+	unsigned long size, unsigned long align, unsigned long min,
+	unsigned int type_mask,
+	void (*alignf)(void *, struct resource *,
+			unsigned long, unsigned long),
+	void *alignf_data)
+{
+	int ret = pci_one_bus_alloc_resource(bus, res, size, align, min,
+					type_mask, alignf, alignf_data);
+
+	/*
+	 * If allocation from the resources available to this bus failed,
+	 * and there is a transparent parent PCI-PCI bridge, we can check
+	 * the resources of the parent bus as well
+	 */
+	while (ret && bus->self && bus->self->transparent) {
+		bus = bus->self->bus;
+		if (!bus)
+			return ret;
+		ret = pci_one_bus_alloc_resource(bus, res, size, align, min,
+					type_mask, alignf, alignf_data);
+	}
+	return ret;
+}
+
+
+/**
  * add a single device
  * @dev: device to add
  *
Index: gregkh-2.6/drivers/pci/pci.c
===================================================================
--- gregkh-2.6.orig/drivers/pci/pci.c	2005-04-12 22:38:38.000000000 -0700
+++ gregkh-2.6/drivers/pci/pci.c	2005-04-12 22:38:42.000000000 -0700
@@ -190,18 +190,13 @@
 }
 
 /**
- * pci_find_parent_resource - return resource region of parent bus of given region
- * @dev: PCI device structure contains resources to be searched
- * @res: child resource record for which parent is sought
+ * pci_bus_find_parent_resource
  *
- *  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.
+ *  Always use pci_find_parent_resource below.
  */
-struct resource *
-pci_find_parent_resource(const struct pci_dev *dev, struct resource *res)
+static struct resource *
+pci_bus_find_parent_resource(const struct pci_bus *bus, struct resource *res)
 {
-	const struct pci_bus *bus = dev->bus;
 	int i;
 	struct resource *best = NULL;
 
@@ -222,6 +217,54 @@
 }
 
 /**
+ * pci_find_parent_resource - return resource region of parent bus of given region
+ * @dev: PCI device structure contains resources to be searched
+ * @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.
+ */
+struct resource *
+pci_find_parent_resource(const struct pci_dev *dev, struct resource *res)
+{
+	struct pci_bus *bus = dev->bus;
+	struct resource *best, *r;
+
+	best = pci_bus_find_parent_resource(bus, res);
+
+	/*
+	 * If there's a transparent parent PCI-PCI bridge, we check the parent
+	 * bus as well in the following occasions:
+	 *  - we didn't find any appropriate resource
+	 *  - res->start and res->end were 0. This is used in code which
+	 *    then wants to request large amounts of IO, so better not limit
+	 *    it to the sub bus. [yenta_socket.c, i2o/iop.c]
+	 *  - we did find a sub-optimal resource (no PREFETCH for PREFETCH)
+	 */
+	while (bus->self && bus->self->transparent &&
+		(!best  || (!res->start && !res->end)
+			|| ((res->flags & IORESOURCE_PREFETCH) &&
+			    !(best->flags & IORESOURCE_PREFETCH)))) {
+		bus = bus->self->bus;
+		if (!bus)
+			return best;
+		r = pci_bus_find_parent_resource(bus, res);
+
+		/*
+		 * If we didn't find an appropriate resource before, use what
+		 * we found in the parent bus; if it's just a matter of
+		 * PREFETCH, only use it if it is optimal.
+		 */
+		if (!best || (!res->start && !res->end)
+			  || ((r->flags & IORESOURCE_PREFETCH) &&
+			      !(best->flags & IORESOURCE_PREFETCH)))
+			best = r;
+	}
+	return best;
+}
+
+/**
  * pci_set_power_state - Set the power state of a PCI device
  * @dev: PCI device to be suspended
  * @state: PCI power state (D0, D1, D2, D3hot, D3cold) we're entering
Index: gregkh-2.6/drivers/pci/probe.c
===================================================================
--- gregkh-2.6.orig/drivers/pci/probe.c	2005-04-12 22:38:38.000000000 -0700
+++ gregkh-2.6/drivers/pci/probe.c	2005-04-12 22:38:42.000000000 -0700
@@ -237,16 +237,10 @@
 	if (!dev)		/* It's a host bus, nothing to read */
 		return;
 
-	if (dev->transparent) {
-		printk(KERN_INFO "PCI: Transparent bridge - %s\n", pci_name(dev));
-		for(i = 0; i < PCI_BUS_NUM_RESOURCES; i++)
-			child->resource[i] = child->parent->resource[i];
-		return;
-	}
-
-	for(i=0; i<3; i++)
+	for (i=0; i<3; i++)
 		child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
 
+	/* Resource 0 - IO ports */
 	res = child->resource[0];
 	pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
 	pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
@@ -267,6 +261,7 @@
 		res->end = limit + 0xfff;
 	}
 
+	/* Resource 1 - nonprefetchable memory resource */
 	res = child->resource[1];
 	pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
 	pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo);
@@ -278,6 +273,7 @@
 		res->end = limit + 0xfffff;
 	}
 
+	/* Resource 2 - prefetchable memory resource */
 	res = child->resource[2];
 	pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
 	pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo);




More information about the linux-pcmcia mailing list