From: Benjamin Herrenschmidt <benh@kernel.crashing.org>
To: Linux kernel mailing list <linux-kernel@vger.kernel.org>
Subject: PCI<->PCI bridges, transparent resource fix
Date: Tue, 6 Aug 2002 20:44:12 +0200 [thread overview]
Message-ID: <20020806184413.17565@192.168.4.1> (raw)
Sorry for those who already got this, it seems there is enough
interest/debate to discuss this here. So here we go...
----
You remember that old debate about how to handle PCI<->PCI bridges
resources that are considered "invalid", should those be transparent or
just closed, etc...
After much thinking (and experiments), I figured out that:
- A "closed" resource could be considered "transparent" without problem.
- The current code for setting up a transparent resource is broken in
a couple of ways. It makes assumptions about the layout of the parent
resources (0 beeing IO, 1 memory, 2 prefetchable memory), while this
is just not true, especially if your parent is the host bridge. It can
also end up setting up both a resource as beeing transparent and one
that is not, which can lead to intresting messup of the resource tree
under some circumstances.
I have reworked the routine along those lines:
- If the IO resource is invalid, consider it transparent by pointing
the bus resources to _all_ parent bus resources of type IO
- If _both_ mem resources are invalid, consider it transparent by
pointing the bus resources to _all_ parent bus resources of type MEM
- if any of the mem resource is invalid and the other valid, just
use the valid one an ignore the invalid one.
Here is a replacement for pci_read_bridges_bases() implementing that
in 2.4 (but the code should move to 2.5 without hitch, I'm not asking
for a merge now, I'm asking for comments/suggestions/brown paper bags ;)
I've quickly tested in on a machine here for which one memory range
was incorrectly considered as transparent and it didn't do anything
bad. I would need you to verify that it still works on real transparent
bridges, or else, help me figure out what I overlooked, the goal here
is to avoid having bazillion of per-bridge special cases.
Regards,
Ben.
static inline int __devinit
add_bus_resource(struct pci_bus *child, struct resource* res)
{
int i;
/* Find free slot */
for(i=0; i<4; i++)
if (child->resource[i] == NULL) {
child->resource[i] = res;
return 1;
}
return 0;
}
static int __devinit
setup_transparent(struct pci_bus *child, unsigned long req_flags)
{
int i;
int found = 0;
/* Iterate parent resources for matching flags */
for(i=0; i<4; i++) {
struct resource* pres = child->parent->resource[i];
if (pres && ((pres->flags & req_flags) != 0)) {
if (!add_bus_resource(child, pres)) {
printk(KERN_ERR "Out of resource slots
for transparent bridge resources\n");
return 0;
}
found = 1;
}
}
return found;
}
/*
* The logic here is as follow:
*
* For each bridge base (IO, mem, mem+prefetch), if the resource appear
* valid, it is added to the resource tree. If not, things are dealt
* differently for IO and mem.
*
* If the IO resource is considered invalid, it's marked transparent,
* that is all of the parent IO ranges are copied down. If the parent
* has no IO ranges, it's considered closed, we don't provide an IO
* resource for this bridge childs.
*
* If at least one the memory resources is considered invalid, we have
* do deal with one of these 3 cases:
*
* - mem invalid, mem+prefetch invalid : This is the simplest case.
* the bridge is either completely transparent for memory cycles or
* completely closed. We copy down all mem resources including
* mem+prefetch from the parent
*
* - mem valid, mem+prefetch invalid : Here, we assume the bridge will
* decode one memory region and is not transparent (the mem+prefetch one
* is considered as closed). We don't copy any resource from the parent
*
* - mem invalid, mem+prefetch valid : Do this case exist ? For now, I
* set it up as non-transparent bridge like the above.
*
* An important goal here is to avoid mixing transparent and non
* transparent resources of the same type. This messes up the resource
* hierarchy and cause allocation failures
*/
void __devinit pci_read_bridge_bases(struct pci_bus *child)
{
struct pci_dev *dev = child->self;
u8 io_base_lo, io_limit_lo;
u16 mem_base_lo, mem_limit_lo;
unsigned long base, limit;
struct resource *res;
int i;
int mem_transp = 0;
if (!dev) /* It's a host bus, nothing to read */
return;
for(i=0; i<4; i++)
child->resource[i] = NULL;
res = &dev->resource[PCI_BRIDGE_RESOURCES];
pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
base = (io_base_lo & PCI_IO_RANGE_MASK) << 8;
limit = (io_limit_lo & PCI_IO_RANGE_MASK) << 8;
if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
u16 io_base_hi, io_limit_hi;
pci_read_config_word(dev, PCI_IO_BASE_UPPER16, &io_base_hi);
pci_read_config_word(dev, PCI_IO_LIMIT_UPPER16, &io_limit_hi);
base |= (unsigned long)(io_base_hi << 16);
limit |= (unsigned long)(io_limit_hi << 16);
}
printk("bridge resource 0, base: %lx, limit: %lx\n", base, limit);
if ((base || limit) && base <= limit) {
res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) |
IORESOURCE_IO;
res->start = base;
res->end = limit + 0xfff;
res->name = child->name;
if (!add_bus_resource(child, res))
printk(KERN_ERR "Out of resource slots for bridge
resource %d: closing...\n", 0);
} else {
if (setup_transparent(child, IORESOURCE_IO))
printk(KERN_ERR "Unknown bridge resource %d:
assuming transparent IO\n", 0);
else
printk(KERN_ERR "Unknown bridge resource %d:
assuming closed\n", 0);
}
res = &dev->resource[PCI_BRIDGE_RESOURCES + 1];
pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo);
base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
printk("bridge resource 1, base: %lx, limit: %lx\n", base, limit);
if (base && base <= limit) {
res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) |
IORESOURCE_MEM;
res->start = base;
res->end = limit + 0xfffff;
res->name = child->name;
if (!add_bus_resource(child, res))
printk(KERN_ERR "Out of resource slots for bridge
resource %d: closing...\n", 1);
} else
mem_transp |= 0x01;
res = &dev->resource[PCI_BRIDGE_RESOURCES + 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);
base = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
limit = (mem_limit_lo & PCI_PREF_RANGE_MASK) << 16;
if ((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) ==
PCI_PREF_RANGE_TYPE_64) {
u32 mem_base_hi, mem_limit_hi;
pci_read_config_dword(dev, PCI_PREF_BASE_UPPER32,
&mem_base_hi);
pci_read_config_dword(dev, PCI_PREF_LIMIT_UPPER32,
&mem_limit_hi);
#if BITS_PER_LONG == 64
base |= ((long) mem_base_hi) << 32;
limit |= ((long) mem_limit_hi) << 32;
#else
if (mem_base_hi || mem_limit_hi) {
printk(KERN_ERR "PCI: Unable to handle 64-bit
address space for %s\n", child->name);
return;
}
#endif
}
printk("bridge resource 2, base: %lx, limit: %lx\n", base, limit);
if (base && base <= limit) {
res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) |
IORESOURCE_MEM | IORESOURCE_PREFETCH;
res->start = base;
res->end = limit + 0xfffff;
res->name = child->name;
if (!add_bus_resource(child, res))
printk(KERN_ERR "Out of resource slots for bridge
resource %d: closing...\n", 2);
}
else
mem_transp |= 0x02;
if (mem_transp == 0x3) {
if (setup_transparent(child, IORESOURCE_MEM))
printk(KERN_ERR "Unknown bridge resource 1 & 2:
assuming transparent MEM\n");
}
}
----------------- Fin du message transmis -----------------
next reply other threads:[~2002-08-06 18:40 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2002-08-06 18:44 Benjamin Herrenschmidt [this message]
[not found] <20020806192951.7E6B44829@dsl2.external.hp.com>
2002-08-06 19:20 ` Benjamin Herrenschmidt
2002-08-07 5:54 ` Grant Grundler
2002-08-06 21:02 ` Benjamin Herrenschmidt
2002-08-07 18:30 ` Grant Grundler
2002-08-08 11:30 ` Ivan Kokshaysky
2002-08-09 7:07 ` Grant Grundler
2002-08-09 8:06 ` Benjamin Herrenschmidt
2002-08-09 17:16 ` Ivan Kokshaysky
[not found] <20020807042402.A4840@jurassic.park.msu.ru>
2002-08-06 20:31 ` Benjamin Herrenschmidt
2002-08-07 16:03 ` Ivan Kokshaysky
2002-08-08 8:20 ` Benjamin Herrenschmidt
2002-08-08 13:21 ` Ivan Kokshaysky
2002-08-09 6:29 ` Benjamin Herrenschmidt
2002-08-09 17:01 ` Ivan Kokshaysky
2002-08-09 21:14 ` Benjamin Herrenschmidt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20020806184413.17565@192.168.4.1 \
--to=benh@kernel.crashing.org \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®