+ release_child_resources(res);Doesn't this recursively release *all* child resources? There could
be BARs from several devices, or even windows of downstream bridges,
inside this window. The drivers of those other devices aren't
expecting things to change here.
+int pci_resize_resource(struct pci_dev *dev, int resno, int size)I think we should fail the request if the device is enabled, i.e., if
+{
+ struct resource *res = dev->resource + resno;
+ u32 sizes = pci_rbar_get_possible_sizes(dev, resno);
+ int old = pci_rbar_get_current_size(dev, resno);
+ u64 bytes = 1ULL << (size + 20);
+ int ret = 0;
the PCI_COMMAND_MEMORY bit is set. We can't safely change the BAR
while memory decoding is enabled.
I know there's code in pci_std_update_resource() that turns off
PCI_COMMAND_MEMORY, but I think that's a mistake: I think it should
fail when asked to update an enabled BAR the same way
pci_iov_update_resource() does.
I'm not sure why you call pci_reenable_device() below, but I think I
would rather have the driver do something like this:
pci_disable_device(dev);
pci_resize_resource(dev, 0, size);
pci_enable_device(dev);
That way it's very clear to the driver that it must re-read all BARs
after resizing this one.
+ if (!sizes)Why do we need to write this zero to the BAR? If PCI_COMMAND_MEMORY
+ return -ENOTSUPP;
+
+ if (!(sizes & (1 << size)))
+ return -EINVAL;
+
+ if (old < 0)
+ return old;
+
+ /* Make sure the resource isn't assigned before making it larger. */
+ if (resource_size(res) < bytes && res->parent) {
+ release_resource(res);
+ res->end = resource_size(res) - 1;
+ res->start = 0;
+ if (resno < PCI_BRIDGE_RESOURCES)
+ pci_update_resource(dev, resno);
is set, I think this is dangerous, and if it's not set, I think it's
unnecessary.
I think we should set the IORESOURCE_UNSET bit to indicate that the
resource does not have an address assigned to it. It should get
cleared later anyway, but having IORESOURCE_UNSET will make any debug
messages emitted while reassigning resources make more sense.
+ return 0;Could this bridge-related recovery code go inside
+
+error_resize:
+ pci_rbar_set_size(dev, resno, old);
+ res->end = res->start + (1ULL << (old + 20)) - 1;
+
+error_reassign:
+ pci_assign_unassigned_bus_resources(dev->bus);
+ pci_setup_bridge(dev->bus);
pci_reassign_bridge_resources()?