aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/setup-bus.c
diff options
context:
space:
mode:
authorYinghai Lu <yinghai@kernel.org>2013-07-25 09:31:38 -0400
committerBjorn Helgaas <bhelgaas@google.com>2013-07-26 09:32:20 -0400
commitaa914f5ec25e4371ba18b312971314be1b9b1076 (patch)
tree318090c34fc438e39c59780bf98e705ce8c50d9e /drivers/pci/setup-bus.c
parentc10cc483bf3f1d0e8f9f077ca36ecc053de9bbbc (diff)
PCI: Retry allocation of only the resource type that failed
Ben Herrenschmidt reported the following problem: - The bus has space for all desired MMIO resources, including optional space for SR-IOV devices - We attempt to allocate I/O port space, but it fails because the bus has no I/O space - Because of the I/O allocation failure, we retry MMIO allocation, requesting only the required space, without the optional SR-IOV space This means we don't allocate the optional SR-IOV space, even though we could. This is related to 0c5be0cb0e ("PCI: Retry on IORESOURCE_IO type allocations"). This patch changes how we handle allocation failures. We will now retry allocation of only the resource type that failed. If MMIO allocation fails, we'll retry only MMIO allocation. If I/O port allocation fails, we'll retry only I/O port allocation. [bhelgaas: changelog] Reference: https://lkml.kernel.org/r/1367712653.11982.19.camel@pasglop Reported-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Tested-by: Gavin Shan <shangw@linux.vnet.ibm.com> Signed-off-by: Yinghai Lu <yinghai@kernel.org> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> CC: stable@vger.kernel.org # v3.10+
Diffstat (limited to 'drivers/pci/setup-bus.c')
-rw-r--r--drivers/pci/setup-bus.c69
1 files changed, 68 insertions, 1 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c
index d254e2379533..64a7de22d9af 100644
--- a/drivers/pci/setup-bus.c
+++ b/drivers/pci/setup-bus.c
@@ -300,6 +300,47 @@ static void assign_requested_resources_sorted(struct list_head *head,
300 } 300 }
301} 301}
302 302
303static unsigned long pci_fail_res_type_mask(struct list_head *fail_head)
304{
305 struct pci_dev_resource *fail_res;
306 unsigned long mask = 0;
307
308 /* check failed type */
309 list_for_each_entry(fail_res, fail_head, list)
310 mask |= fail_res->flags;
311
312 /*
313 * one pref failed resource will set IORESOURCE_MEM,
314 * as we can allocate pref in non-pref range.
315 * Will release all assigned non-pref sibling resources
316 * according to that bit.
317 */
318 return mask & (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH);
319}
320
321static bool pci_need_to_release(unsigned long mask, struct resource *res)
322{
323 if (res->flags & IORESOURCE_IO)
324 return !!(mask & IORESOURCE_IO);
325
326 /* check pref at first */
327 if (res->flags & IORESOURCE_PREFETCH) {
328 if (mask & IORESOURCE_PREFETCH)
329 return true;
330 /* count pref if its parent is non-pref */
331 else if ((mask & IORESOURCE_MEM) &&
332 !(res->parent->flags & IORESOURCE_PREFETCH))
333 return true;
334 else
335 return false;
336 }
337
338 if (res->flags & IORESOURCE_MEM)
339 return !!(mask & IORESOURCE_MEM);
340
341 return false; /* should not get here */
342}
343
303static void __assign_resources_sorted(struct list_head *head, 344static void __assign_resources_sorted(struct list_head *head,
304 struct list_head *realloc_head, 345 struct list_head *realloc_head,
305 struct list_head *fail_head) 346 struct list_head *fail_head)
@@ -312,11 +353,24 @@ static void __assign_resources_sorted(struct list_head *head,
312 * if could do that, could get out early. 353 * if could do that, could get out early.
313 * if could not do that, we still try to assign requested at first, 354 * if could not do that, we still try to assign requested at first,
314 * then try to reassign add_size for some resources. 355 * then try to reassign add_size for some resources.
356 *
357 * Separate three resource type checking if we need to release
358 * assigned resource after requested + add_size try.
359 * 1. if there is io port assign fail, will release assigned
360 * io port.
361 * 2. if there is pref mmio assign fail, release assigned
362 * pref mmio.
363 * if assigned pref mmio's parent is non-pref mmio and there
364 * is non-pref mmio assign fail, will release that assigned
365 * pref mmio.
366 * 3. if there is non-pref mmio assign fail or pref mmio
367 * assigned fail, will release assigned non-pref mmio.
315 */ 368 */
316 LIST_HEAD(save_head); 369 LIST_HEAD(save_head);
317 LIST_HEAD(local_fail_head); 370 LIST_HEAD(local_fail_head);
318 struct pci_dev_resource *save_res; 371 struct pci_dev_resource *save_res;
319 struct pci_dev_resource *dev_res; 372 struct pci_dev_resource *dev_res, *tmp_res;
373 unsigned long fail_type;
320 374
321 /* Check if optional add_size is there */ 375 /* Check if optional add_size is there */
322 if (!realloc_head || list_empty(realloc_head)) 376 if (!realloc_head || list_empty(realloc_head))
@@ -348,6 +402,19 @@ static void __assign_resources_sorted(struct list_head *head,
348 return; 402 return;
349 } 403 }
350 404
405 /* check failed type */
406 fail_type = pci_fail_res_type_mask(&local_fail_head);
407 /* remove not need to be released assigned res from head list etc */
408 list_for_each_entry_safe(dev_res, tmp_res, head, list)
409 if (dev_res->res->parent &&
410 !pci_need_to_release(fail_type, dev_res->res)) {
411 /* remove it from realloc_head list */
412 remove_from_list(realloc_head, dev_res->res);
413 remove_from_list(&save_head, dev_res->res);
414 list_del(&dev_res->list);
415 kfree(dev_res);
416 }
417
351 free_list(&local_fail_head); 418 free_list(&local_fail_head);
352 /* Release assigned resource */ 419 /* Release assigned resource */
353 list_for_each_entry(dev_res, head, list) 420 list_for_each_entry(dev_res, head, list)