|
Jesse Keating |
3494df0 |
From: Bjorn Helgaas <bjorn.helgaas@hp.com>
|
|
Jesse Keating |
3494df0 |
Date: Thu, 15 Jul 2010 15:41:42 +0000 (-0600)
|
|
Jesse Keating |
3494df0 |
Subject: PCI: fall back to original BIOS BAR addresses
|
|
Jesse Keating |
3494df0 |
X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=58c84eda07560a6b75b03e8d3b26d6eddfc14011
|
|
Jesse Keating |
3494df0 |
|
|
Jesse Keating |
3494df0 |
PCI: fall back to original BIOS BAR addresses
|
|
Jesse Keating |
3494df0 |
|
|
Jesse Keating |
3494df0 |
If we fail to assign resources to a PCI BAR, this patch makes us try the
|
|
Jesse Keating |
3494df0 |
original address from BIOS rather than leaving it disabled.
|
|
Jesse Keating |
3494df0 |
|
|
Jesse Keating |
3494df0 |
Linux tries to make sure all PCI device BARs are inside the upstream
|
|
Jesse Keating |
3494df0 |
PCI host bridge or P2P bridge apertures, reassigning BARs if necessary.
|
|
Jesse Keating |
3494df0 |
Windows does similar reassignment.
|
|
Jesse Keating |
3494df0 |
|
|
Jesse Keating |
3494df0 |
Before this patch, if we could not move a BAR into an aperture, we left
|
|
Jesse Keating |
3494df0 |
the resource unassigned, i.e., at address zero. Windows leaves such BARs
|
|
Jesse Keating |
3494df0 |
at the original BIOS addresses, and this patch makes Linux do the same.
|
|
Jesse Keating |
3494df0 |
|
|
Jesse Keating |
3494df0 |
This is a bit ugly because we disable the resource long before we try to
|
|
Jesse Keating |
3494df0 |
reassign it, so we have to keep track of the BIOS BAR address somewhere.
|
|
Jesse Keating |
3494df0 |
For lack of a better place, I put it in the struct pci_dev.
|
|
Jesse Keating |
3494df0 |
|
|
Jesse Keating |
3494df0 |
I think it would be cleaner to attempt the assignment immediately when the
|
|
Jesse Keating |
3494df0 |
claim fails, so we could easily remember the original address. But we
|
|
Jesse Keating |
3494df0 |
currently claim motherboard resources in the middle, after attempting to
|
|
Jesse Keating |
3494df0 |
claim PCI resources and before assigning new PCI resources, and changing
|
|
Jesse Keating |
3494df0 |
that is a fairly big job.
|
|
Jesse Keating |
3494df0 |
|
|
Jesse Keating |
3494df0 |
Addresses https://bugzilla.kernel.org/show_bug.cgi?id=16263
|
|
Jesse Keating |
3494df0 |
|
|
Jesse Keating |
3494df0 |
Reported-by: Andrew <nitr0@seti.kr.ua>
|
|
Jesse Keating |
3494df0 |
Tested-by: Andrew <nitr0@seti.kr.ua>
|
|
Jesse Keating |
3494df0 |
Signed-off-by: Bjorn Helgaas <bjorn.helgaas@hp.com>
|
|
Jesse Keating |
3494df0 |
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
|
|
Jesse Keating |
3494df0 |
---
|
|
Jesse Keating |
3494df0 |
|
|
Jesse Keating |
3494df0 |
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
|
|
Jesse Keating |
3494df0 |
index 6fdb3ec..5525309 100644
|
|
Jesse Keating |
3494df0 |
--- a/arch/x86/pci/i386.c
|
|
Jesse Keating |
3494df0 |
+++ b/arch/x86/pci/i386.c
|
|
Jesse Keating |
3494df0 |
@@ -184,6 +184,7 @@ static void __init pcibios_allocate_resources(int pass)
|
|
Jesse Keating |
3494df0 |
idx, r, disabled, pass);
|
|
Jesse Keating |
3494df0 |
if (pci_claim_resource(dev, idx) < 0) {
|
|
Jesse Keating |
3494df0 |
/* We'll assign a new address later */
|
|
Jesse Keating |
3494df0 |
+ dev->fw_addr[idx] = r->start;
|
|
Jesse Keating |
3494df0 |
r->end -= r->start;
|
|
Jesse Keating |
3494df0 |
r->start = 0;
|
|
Jesse Keating |
3494df0 |
}
|
|
Jesse Keating |
3494df0 |
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
|
|
Jesse Keating |
3494df0 |
index 92379e2..2aaa131 100644
|
|
Jesse Keating |
3494df0 |
--- a/drivers/pci/setup-res.c
|
|
Jesse Keating |
3494df0 |
+++ b/drivers/pci/setup-res.c
|
|
Jesse Keating |
3494df0 |
@@ -156,6 +156,38 @@ static int __pci_assign_resource(struct pci_bus *bus, struct pci_dev *dev,
|
|
Jesse Keating |
3494df0 |
pcibios_align_resource, dev);
|
|
Jesse Keating |
3494df0 |
}
|
|
Jesse Keating |
3494df0 |
|
|
Jesse Keating |
3494df0 |
+ if (ret < 0 && dev->fw_addr[resno]) {
|
|
Jesse Keating |
3494df0 |
+ struct resource *root, *conflict;
|
|
Jesse Keating |
3494df0 |
+ resource_size_t start, end;
|
|
Jesse Keating |
3494df0 |
+
|
|
Jesse Keating |
3494df0 |
+ /*
|
|
Jesse Keating |
3494df0 |
+ * If we failed to assign anything, let's try the address
|
|
Jesse Keating |
3494df0 |
+ * where firmware left it. That at least has a chance of
|
|
Jesse Keating |
3494df0 |
+ * working, which is better than just leaving it disabled.
|
|
Jesse Keating |
3494df0 |
+ */
|
|
Jesse Keating |
3494df0 |
+
|
|
Jesse Keating |
3494df0 |
+ if (res->flags & IORESOURCE_IO)
|
|
Jesse Keating |
3494df0 |
+ root = &ioport_resource;
|
|
Jesse Keating |
3494df0 |
+ else
|
|
Jesse Keating |
3494df0 |
+ root = &iomem_resource;
|
|
Jesse Keating |
3494df0 |
+
|
|
Jesse Keating |
3494df0 |
+ start = res->start;
|
|
Jesse Keating |
3494df0 |
+ end = res->end;
|
|
Jesse Keating |
3494df0 |
+ res->start = dev->fw_addr[resno];
|
|
Jesse Keating |
3494df0 |
+ res->end = res->start + size - 1;
|
|
Jesse Keating |
3494df0 |
+ dev_info(&dev->dev, "BAR %d: trying firmware assignment %pR\n",
|
|
Jesse Keating |
3494df0 |
+ resno, res);
|
|
Jesse Keating |
3494df0 |
+ conflict = request_resource_conflict(root, res);
|
|
Jesse Keating |
3494df0 |
+ if (conflict) {
|
|
Jesse Keating |
3494df0 |
+ dev_info(&dev->dev,
|
|
Jesse Keating |
3494df0 |
+ "BAR %d: %pR conflicts with %s %pR\n", resno,
|
|
Jesse Keating |
3494df0 |
+ res, conflict->name, conflict);
|
|
Jesse Keating |
3494df0 |
+ res->start = start;
|
|
Jesse Keating |
3494df0 |
+ res->end = end;
|
|
Jesse Keating |
3494df0 |
+ } else
|
|
Jesse Keating |
3494df0 |
+ ret = 0;
|
|
Jesse Keating |
3494df0 |
+ }
|
|
Jesse Keating |
3494df0 |
+
|
|
Jesse Keating |
3494df0 |
if (!ret) {
|
|
Jesse Keating |
3494df0 |
res->flags &= ~IORESOURCE_STARTALIGN;
|
|
Jesse Keating |
3494df0 |
dev_info(&dev->dev, "BAR %d: assigned %pR\n", resno, res);
|
|
Jesse Keating |
3494df0 |
diff --git a/include/linux/pci.h b/include/linux/pci.h
|
|
Jesse Keating |
3494df0 |
index 7cb0084..f26fda7 100644
|
|
Jesse Keating |
3494df0 |
--- a/include/linux/pci.h
|
|
Jesse Keating |
3494df0 |
+++ b/include/linux/pci.h
|
|
Jesse Keating |
3494df0 |
@@ -288,6 +288,7 @@ struct pci_dev {
|
|
Jesse Keating |
3494df0 |
*/
|
|
Jesse Keating |
3494df0 |
unsigned int irq;
|
|
Jesse Keating |
3494df0 |
struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */
|
|
Jesse Keating |
3494df0 |
+ resource_size_t fw_addr[DEVICE_COUNT_RESOURCE]; /* FW-assigned addr */
|
|
Jesse Keating |
3494df0 |
|
|
Jesse Keating |
3494df0 |
/* These fields are used by common fixups */
|
|
Jesse Keating |
3494df0 |
unsigned int transparent:1; /* Transparent PCI bridge */
|