Re: PCI hotplug problems: how to debug?

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

 



On Thursday 05 November 2009 04:31:11 pm Ira W. Snyder wrote:
> On Thu, Nov 05, 2009 at 04:00:41PM -0600, Bjorn Helgaas wrote:
> 
> [ big snip ]
> 
> > 
> > On Trenton, the device is directly below a host bridge, and we don't
> > know the host bridge apertures, so I think we're picking assignments
> > that don't work.
> > 
> > Can you turn on CONFIG_PCI_DEBUG and try the patch below?  It has a
> > hack to try to make the assignments use the same BAR values as BIOS
> > gave us, and a couple printks to find out more about why we try to
> > assign resources at all.  Sorry for the brute-force debugging; I
> > don't know enough to do it more elegantly.
> 
> Both are attached.
> 
> Looking at your patch, you did something special with the Trenton. It
> worked! I even reset the card for the last scan. You can see that the
> BAR's were initially zeroed, then Linux set them.
> 
> How did you choose the addresses to set for the Trenton's bridge? I'm
> guessing it would change with lots of cards on that PCI bus. Right now I
> only have one card, but pretty soon I'll have more. :)

The pci_bus 0000:01 resources are basically our idea of the host
bridge apertures, so I just picked ranges that include the original
01:0b.0 BAR settings from BIOS.

The assignments done by Linux are in a different order, but still in
the original ranges.

[    0.492043] pci 0000:01:0b.0: reg 10: [mem 0xfeb00000-0xfebfffff]
[    0.496020] pci 0000:01:0b.0: reg 14: [mem 0xfbfff000-0xfbffffff pref]
[    0.500028] pci 0000:01:0b.0: reg 18: [mem 0xfbe00000-0xfbefffff 64bit pref]
[    0.504028] pci 0000:01:0b.0: reg 20: [mem 0xfbd00000-0xfbdfffff 64bit pref]

[  312.295286] pci 0000:01:0b.0: removing device
[  315.998301] pci_bus 0000:01: rescanning bus
[  316.010334] pci 0000:01:0b.0: reg 10: [mem 0xfeb00000-0xfebfffff]
[  316.014309] pci 0000:01:0b.0: reg 14: [mem 0xfbfff000-0xfbffffff pref]
[  316.018318] pci 0000:01:0b.0: reg 18: [mem 0xfbe00000-0xfbefffff 64bit pref]
[  316.022318] pci 0000:01:0b.0: reg 20: [mem 0xfbd00000-0xfbdfffff 64bit pref]

[  316.078337] pci 0000:01:0b.0: BAR 0: assigned [mem 0xfeb00000-0xfebfffff]
[  316.102303] pci 0000:01:0b.0: BAR 1: assigned [mem 0xfbf00000-0xfbf00fff pref]
[  316.086304] pci 0000:01:0b.0: BAR 2: assigned [mem 0xfbd00000-0xfbdfffff 64bit pref]
[  316.094303] pci 0000:01:0b.0: BAR 4: assigned [mem 0xfbe00000-0xfbefffff 64bit pref]

During initial boot, we claim PCI resources in pcibios_allocate_resources().
This sets r->parent, so we don't attempt to reassign the BARs later.  But
when we rescan the bus, there's nothing that claims the resources we find.

I'm sure there's some reason why the attached patch can't be done in
general, but can you try it out?  My intent is that it would try to
claim the resources of devices we find when rescanning the bus, so we
would just use the current assignments.

Of course, this doesn't help if you actually power off the slot or
press your reset button.  In that case, we have to assign things from
scratch, and we really need to know what the host bridge apertures are.
It'd be best if the BIOS gave us an ACPI description, so we could just
use "pci=use_crs".  Without that, I think we'll need a host bridge
driver to read them out of the hardware, and it sounds like we don't
have the specs required to write such a driver.

Bjorn


diff --git a/arch/x86/pci/common.c b/arch/x86/pci/common.c
index 1331fcf..2fc835e 100644
--- a/arch/x86/pci/common.c
+++ b/arch/x86/pci/common.c
@@ -593,6 +593,29 @@ struct pci_bus * __devinit pci_scan_bus_on_node(int busno, struct pci_ops *ops,
 	if (!bus)
 		kfree(sd);
 
+	if (0 && bus->number == 1) {
+		struct resource *res;
+
+		dev_info(&bus->dev, "test kludge for Trenton\n");
+		dev_info(&bus->dev, "resource 1 %pR\n", bus->resource[1]);
+		dev_info(&bus->dev, "resource 2 %pR\n", bus->resource[2]);
+		res = kzalloc(sizeof(*res), GFP_KERNEL);
+		if (res) {
+			res->start = 0xfeb00000;
+			res->end = 0xfebfffff;
+			res->flags = IORESOURCE_MEM;
+			bus->resource[1] = res;
+		}
+		res = kzalloc(sizeof(*res), GFP_KERNEL);
+		if (res) {
+			res->start = 0xfbd00000;
+			res->end = 0xfbffffff;
+			res->flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
+			bus->resource[2] = res;
+		}
+		dev_info(&bus->dev, "resource 1 %pR\n", bus->resource[1]);
+		dev_info(&bus->dev, "resource 2 %pR\n", bus->resource[2]);
+	}
 	return bus;
 }
 
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 5c4ce1b..4d66925 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1101,6 +1101,32 @@ int pci_scan_slot(struct pci_bus *bus, int devfn)
 	return nr;
 }
 
+static void pci_claim_resources(struct pci_dev *dev)
+{
+	u16 command;
+	int i, io_enabled, mem_enabled;
+	struct resource *r;
+
+	pci_read_config_word(dev, PCI_COMMAND, &command);
+	io_enabled = (command & PCI_COMMAND_IO);
+	mem_enabled = (command & PCI_COMMAND_MEMORY);
+	for (i = 0; i < PCI_ROM_RESOURCE; i++) {
+		r = &dev->resource[i];
+		if (r->parent)
+			continue;
+		if (!r->start)
+			continue;
+
+		if (((r->flags & IORESOURCE_IO) && io_enabled) ||
+		    ((r->flags & IORESOURCE_MEM) && mem_enabled)) {
+			dev_printk(KERN_DEBUG, &dev->dev,
+				   "BAR %d: reserving %pr\n", i, r);
+			if (pci_claim_resource(dev, i) < 0)
+				dev_info(&dev->dev, "can't reserve %pR\n", r);
+		}
+	}
+}
+
 unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
 {
 	unsigned int devfn, pass, max = bus->secondary;
@@ -1133,6 +1159,9 @@ unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus)
 				max = pci_scan_bridge(bus, dev, max, pass);
 		}
 
+	list_for_each_entry(dev, &bus->devices, bus_list)
+		pci_claim_resources(dev);
+
 	/*
 	 * We've scanned the bus and so we know all about what's on
 	 * the other side of any bridges that may be on this bus plus
@@ -1246,6 +1275,7 @@ unsigned int __ref pci_rescan_bus(struct pci_bus *bus)
 	unsigned int max;
 	struct pci_dev *dev;
 
+	dev_info(&bus->dev, "rescanning bus\n");
 	max = pci_scan_child_bus(bus);
 
 	down_read(&pci_bus_sem);
diff --git a/drivers/pci/remove.c b/drivers/pci/remove.c
index 176615e..a12930c 100644
--- a/drivers/pci/remove.c
+++ b/drivers/pci/remove.c
@@ -64,6 +64,7 @@ int pci_remove_device_safe(struct pci_dev *dev)
 
 void pci_remove_bus(struct pci_bus *pci_bus)
 {
+	dev_info(&pci_bus->dev, "removing bus\n");
 	pci_proc_detach_bus(pci_bus);
 
 	down_write(&pci_bus_sem);
@@ -93,6 +94,7 @@ EXPORT_SYMBOL(pci_remove_bus);
  */
 void pci_remove_bus_device(struct pci_dev *dev)
 {
+	dev_info(&dev->dev, "removing device\n");
 	pci_stop_bus_device(dev);
 	if (dev->subordinate) {
 		struct pci_bus *b = dev->subordinate;
diff --git a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c
index 7d678bb..27b0eb4 100644
--- a/drivers/pci/setup-res.c
+++ b/drivers/pci/setup-res.c
@@ -223,6 +223,7 @@ void pdev_sort_resources(struct pci_dev *dev, struct resource_list *head)
 		if (r->flags & IORESOURCE_PCI_FIXED)
 			continue;
 
+		dev_info(&dev->dev, "pdev_sort_resources: res %d %pR parent %pR\n", i, r, r->parent);
 		if (!(r->flags) || r->parent)
 			continue;
 
--
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