Re: [PATCH] Add pci=assign-busses quirk to Dell Latitude D505

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

 



[+cc Thomas, your regression has probably the same cause]

This looks a like it is going to be a little more complicated than anticipated.

pci_scan_bus has two main branches. One for "broken" hardware and cardbus and
another one for bridges whose configuration looks sane.

David's working 3.2 Kernel does the following:
pci 0000:00:1e.0: PCI bridge to [bus 01-01] (subtractive decode)
pci 0000:01:01.0: bridge configuration invalid ([bus 00-00]), reconfiguring

The 00:1e bridge is deemed sane and the 01:01 (cardbus) bridge below it is
deemed broken. pci_scan_bridge than assigns bus [2-5] to 01:01 without touching
1e (so we just got 4 imaginary busses). We just print a warning:
pci_bus 0000:02: [bus 02-05] partially hidden behind transparent bridge 0000:01 [bus 01-01]

After returning to 00:1e (in the sane branch) we also do not update our
subordinate and just return. Later yenta_socket sees that this is nuts and
carefully increases the subordinate of 00:1e.

My patch series for 3.15 was trying to make sure that pci_scan_bus does not
overstep its resources. So now we now refuse to create bus 2 under [01-01]
(fc1b2531 PCI: Don't scan random busses in pci_scan_bridge()) and a little
later we would forbid the cardbus code in pci_scan_bridge from reserving 4 more
busses (1820ffdc PCI: Make sure bus number resources stay within their parents
bounds). At least these two would need to be reverted.

As an alternative the following patch tries grow the bus window, if necessary
by growing its parents bus window (recursively). This should make the yenta
fixup unnecessary. I have tested the patch with normal pci bridges + setpci,
since I don't have access to a cardbus system.

So if you have time please test this and/or try to revert the two mentioned
commits.

Thanks,
Andreas
---
 drivers/pci/probe.c | 45 ++++++++++++++++++++++++++++++++++++---------
 1 file changed, 36 insertions(+), 9 deletions(-)

diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index e3cf8a2..81dd668 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -740,6 +740,30 @@ struct pci_bus *pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev,
 }
 EXPORT_SYMBOL(pci_add_new_bus);
 
+int pci_grow_bus(struct pci_bus *bus, int bus_max)
+{
+	struct resource *res = &bus->busn_res;
+	struct resource old_res = *res;
+	int ret;
+	if (res->end >= bus_max)
+		return 0;
+	if (!bus->self || pci_is_root_bus(bus)) {
+		dev_printk(KERN_DEBUG, &bus->dev,
+			   "root busn_res %pR cannot grow\n", &res);
+		return -EBUSY;
+	}
+	ret = pci_grow_bus(bus->parent, bus_max);
+	if (ret)
+		return ret;
+	ret = adjust_resource(res, res->start, bus_max - res->start + 1);
+	dev_printk(KERN_DEBUG, &bus->dev,
+			"busn_res: %pR end %s grown to %02x\n",
+			&old_res, ret ? "cannot be" : "has", bus_max);
+
+	pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, bus_max);
+	return ret;
+}
+
 /*
  * If it's a bridge, configure it and scan the bus behind it.
  * For CardBus bridges, we don't scan behind as the devices will
@@ -814,12 +838,11 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
 		}
 
 		cmax = pci_scan_child_bus(child);
-		if (cmax > subordinate)
-			dev_warn(&dev->dev, "bridge has subordinate %02x but max busn %02x\n",
-				 subordinate, cmax);
-		/* subordinate should equal child->busn_res.end */
-		if (subordinate > max)
-			max = subordinate;
+		if (cmax > child->busn_res.end)
+			dev_warn(&dev->dev, "bridge has bus resource %pR but max busn %02x\n",
+				 &child->busn_res, cmax);
+		if (child->busn_res.end > max)
+			max = child->busn_res.end;
 	} else {
 		/*
 		 * We need to assign a number to this bus which we always
@@ -840,8 +863,10 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
 
 		if (max >= bus->busn_res.end) {
 			dev_warn(&dev->dev, "can't allocate child bus %02x from %pR\n",
-				 max, &bus->busn_res);
-			goto out;
+				 max + 1, &bus->busn_res);
+			/* Try to resize bus */
+			if (pci_grow_bus(bus, max + 1))
+				goto out;
 		}
 
 		/* Clear errors */
@@ -908,6 +933,7 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
 					break;
 				}
 			}
+			dev_info(&dev->dev, "adding %02x bus numbers for cardbus\n", i);
 			max += i;
 		}
 		/*
@@ -916,7 +942,8 @@ int pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max, int pass)
 		if (max > bus->busn_res.end) {
 			dev_warn(&dev->dev, "max busn %02x is outside %pR\n",
 				 max, &bus->busn_res);
-			max = bus->busn_res.end;
+			if (pci_grow_bus(bus, max))
+				max = bus->busn_res.end;
 		}
 		pci_bus_update_busn_res_end(child, max);
 		pci_write_config_byte(dev, PCI_SUBORDINATE_BUS, max);
-- 
2.1.0

--
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