// SPDX-License-Identifier: GPL-2.0/* * Support routines for initializing a PCI subsystem * * Extruded from code written by * Dave Rusling (david.rusling@reo.mts.dec.com) * David Mosberger (davidm@cs.arizona.edu) * David Miller (davem@redhat.com) * * Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru> * PCI-PCI bridges cleanup, sorted resource allocation. * Feb 2002, Ivan Kokshaysky <ink@jurassic.park.msu.ru> * Converted to allocation in 3 passes, which gives * tighter packing. Prefetchable range support. */ #include <linux/align.h>#include <linux/bitops.h>#include <linux/bug.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/minmax.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/cache.h>#include <linux/limits.h>#include <linux/sizes.h>#include <linux/slab.h>#include <linux/acpi.h>#include "pci.h" #define PCI_RES_TYPE_MASK \ (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH |\ IORESOURCE_MEM_64) unsigned int pci_flags;EXPORT_SYMBOL_GPL(pci_flags); struct pci_dev_resource { struct list_head list; struct resource *res; struct pci_dev *dev; resource_size_t start; resource_size_t end; resource_size_t add_size; resource_size_t min_align; unsigned long flags;}; static void pci_dev_res_free_list(struct list_head *head){ struct pci_dev_resource *dev_res, *tmp; list_for_each_entry_safe(dev_res, tmp, head, list) { list_del(&dev_res->list); kfree(dev_res); }} /** * pci_dev_res_add_to_list() - Add a new resource tracker to the list * @head: Head of the list * @dev: Device to which the resource belongs * @res: Resource to be tracked * @add_size: Additional size to be optionally added to the resource * @min_align: Minimum memory window alignment */int pci_dev_res_add_to_list(struct list_head *head, struct pci_dev *dev, struct resource *res, resource_size_t add_size, resource_size_t min_align){ struct pci_dev_resource *tmp; tmp = kzalloc_obj(*tmp); if (!tmp) return -ENOMEM; tmp->res = res; tmp->dev = dev; tmp->start = res->start; tmp->end = res->end; tmp->flags = res->flags; tmp->add_size = add_size; tmp->min_align = min_align; list_add(&tmp->list, head); return 0;} static void pci_dev_res_remove_from_list(struct list_head *head, struct resource *res){ struct pci_dev_resource *dev_res, *tmp; list_for_each_entry_safe(dev_res, tmp, head, list) { if (dev_res->res == res) { list_del(&dev_res->list); kfree(dev_res); break; } }} static struct pci_dev_resource *res_to_dev_res(struct list_head *head, struct resource *res){ struct pci_dev_resource *dev_res; list_for_each_entry(dev_res, head, list) { if (dev_res->res == res) return dev_res; } return NULL;} static resource_size_t get_res_add_size(struct list_head *head, struct resource *res){ struct pci_dev_resource *dev_res; dev_res = res_to_dev_res(head, res); return dev_res ? dev_res->add_size : 0;} static void pci_dev_res_restore(struct pci_dev_resource *dev_res){ struct resource *res = dev_res->res; struct pci_dev *dev = dev_res->dev; int idx = pci_resource_num(dev, res); const char *res_name = pci_resource_name(dev, idx); if (WARN_ON_ONCE(resource_assigned(res))) return; res->start = dev_res->start; res->end = dev_res->end; res->flags = dev_res->flags; pci_dbg(dev, "%s %pR: resource restored\n", res_name, res);} /* * Helper function for sizing routines. Assigned resources have non-NULL * parent resource. * * Return first unassigned resource of the correct type. If there is none, * return first assigned resource of the correct type. If none of the * above, return NULL. * * Returning an assigned resource of the correct type allows the caller to * distinguish between already assigned and no resource of the correct type. */static struct resource *find_bus_resource_of_type(struct pci_bus *bus, unsigned long type_mask, unsigned long type){ struct resource *r, *r_assigned = NULL; pci_bus_for_each_resource(bus, r) { if (!r || r == &ioport_resource || r == &iomem_resource) continue; if ((r->flags & type_mask) != type) continue; if (!resource_assigned(r)) return r; if (!r_assigned) r_assigned = r; } return r_assigned;} /** * pbus_select_window_for_type - Select bridge window for a resource type * @bus: PCI bus * @type: Resource type (resource flags can be passed as is) * * Select the bridge window based on a resource @type. * * For memory resources, the selection is done as follows: * * Any non-prefetchable resource is put into the non-prefetchable window. * * If there is no prefetchable MMIO window, put all memory resources into the * non-prefetchable window. * * If there's a 64-bit prefetchable MMIO window, put all 64-bit prefetchable * resources into it and place 32-bit prefetchable memory into the * non-prefetchable window. * * Otherwise, put all prefetchable resources into the prefetchable window. * * Return: the bridge window resource or NULL if no bridge window is found. */static struct resource *pbus_select_window_for_type(struct pci_bus *bus, unsigned long type){ int iores_type = type & IORESOURCE_TYPE_BITS; /* w/o 64bit & pref */ struct resource *mmio, *mmio_pref, *win; type &= PCI_RES_TYPE_MASK; /* with 64bit & pref */ if ((iores_type != IORESOURCE_IO) && (iores_type != IORESOURCE_MEM)) return NULL; if (pci_is_root_bus(bus)) { win = find_bus_resource_of_type(bus, type, type); if (win) return win; type &= ~IORESOURCE_MEM_64; win = find_bus_resource_of_type(bus, type, type); if (win) return win; type &= ~IORESOURCE_PREFETCH; return find_bus_resource_of_type(bus, type, type); } switch (iores_type) { case IORESOURCE_IO: win = pci_bus_resource_n(bus, PCI_BUS_BRIDGE_IO_WINDOW); if (win && (win->flags & IORESOURCE_IO)) return win; return NULL; case IORESOURCE_MEM: mmio = pci_bus_resource_n(bus, PCI_BUS_BRIDGE_MEM_WINDOW); mmio_pref = pci_bus_resource_n(bus, PCI_BUS_BRIDGE_PREF_MEM_WINDOW); if (mmio && !(mmio->flags & IORESOURCE_MEM)) mmio = NULL; if (mmio_pref && !(mmio_pref->flags & IORESOURCE_MEM)) mmio_pref = NULL; if (!(type & IORESOURCE_PREFETCH) || !mmio_pref) return mmio; if ((type & IORESOURCE_MEM_64) || !(mmio_pref->flags & IORESOURCE_MEM_64)) return mmio_pref; return mmio; default: return NULL; }} /** * pbus_select_window - Select bridge window for a resource * @bus: PCI bus * @res: Resource * * Select the bridge window for @res. If the resource is already assigned, * return the current bridge window. * * For memory resources, the selection is done as follows: * * Any non-prefetchable resource is put into the non-prefetchable window. * * If there is no prefetchable MMIO window, put all memory resources into the * non-prefetchable window. * * If there's a 64-bit prefetchable MMIO window, put all 64-bit prefetchable * resources into it and place 32-bit prefetchable memory into the * non-prefetchable window. * * Otherwise, put all prefetchable resources into the prefetchable window. * * Return: the bridge window resource or NULL if no bridge window is found. */struct resource *pbus_select_window(struct pci_bus *bus, const struct resource *res){ if (resource_assigned(res)) return res->parent; return pbus_select_window_for_type(bus, res->flags);} static bool pdev_resources_assignable(struct pci_dev *dev){ u16 class = dev->class >> 8, command; /* Don't touch classless devices or host bridges or IOAPICs */ if (class == PCI_CLASS_NOT_DEFINED || class == PCI_CLASS_BRIDGE_HOST) return false; /* Don't touch IOAPIC devices already enabled by firmware */ if (class == PCI_CLASS_SYSTEM_PIC) { pci_read_config_word(dev, PCI_COMMAND, &command); if (command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) return false; } return true;} static bool pdev_resource_assignable(struct pci_dev *dev, struct resource *res){ int idx = pci_resource_num(dev, res); if (!res->flags) return false; if (pci_resource_is_bridge_win(idx) && res->flags & IORESOURCE_DISABLED) return false; return true;} static bool pdev_resource_should_fit(struct pci_dev *dev, struct resource *res){ if (resource_assigned(res)) return false; if (res->flags & IORESOURCE_PCI_FIXED) return false; return pdev_resource_assignable(dev, res);} /* Sort resources by alignment */static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head){ struct resource *r; int i; if (!pdev_resources_assignable(dev)) return; pci_dev_for_each_resource(dev, r, i) { const char *r_name = pci_resource_name(dev, i); struct pci_dev_resource *dev_res, *tmp; resource_size_t r_align; struct list_head *n; if (!pdev_resource_should_fit(dev, r)) continue; r_align = pci_resource_alignment(dev, r); if (!r_align) { pci_warn(dev, "%s %pR: alignment must not be zero\n", r_name, r); continue; } tmp = kzalloc_obj(*tmp); if (!tmp) panic("%s: kzalloc() failed!\n", __func__); tmp->res = r; tmp->dev = dev; tmp->start = r->start; tmp->end = r->end; tmp->flags = r->flags; /* Fallback is smallest one or list is empty */ n = head; list_for_each_entry(dev_res, head, list) { resource_size_t align; align = pci_resource_alignment(dev_res->dev, dev_res->res); if (r_align > align) { n = &dev_res->list; break; } } /* Insert it just before n */ list_add_tail(&tmp->list, n); }} bool pci_resource_is_optional(const struct pci_dev *dev, int resno){ const struct resource *res = pci_resource_n(dev, resno); if (pci_resource_is_iov(resno)) return true; if (resno == PCI_ROM_RESOURCE && !(res->flags & IORESOURCE_ROM_ENABLE)) return true; if (pci_resource_is_bridge_win(resno) && !resource_size(res)) return true; return false;} static void reset_resource(struct pci_dev *dev, struct resource *res){ int idx = pci_resource_num(dev, res); const char *res_name = pci_resource_name(dev, idx); if (pci_resource_is_bridge_win(idx)) { res->flags |= IORESOURCE_UNSET; return; } pci_dbg(dev, "%s %pR: resetting resource\n", res_name, res); res->start = 0; res->end = 0; res->flags = 0;} /** * reassign_resources_sorted() - Satisfy any additional resource requests * * @realloc_head: Head of the list tracking requests requiring * additional resources * @head: Head of the list tracking requests with allocated * resources * * Walk through each element of the realloc_head and try to procure additional * resources for the element, provided the element is in the head list. */static void reassign_resources_sorted(struct list_head *realloc_head, struct list_head *head){ struct pci_dev_resource *add_res, *tmp; struct pci_dev *dev; struct resource *res; const char *res_name; resource_size_t add_size, align; int idx; list_for_each_entry_safe(add_res, tmp, realloc_head, list) { res = add_res->res; dev = add_res->dev; idx = pci_resource_num(dev, res); /* Skip this resource if not found in head list */ if (!res_to_dev_res(head, res)) continue; /* * Skip resource that failed the earlier assignment and is * not optional as it would just fail again. */ if (!resource_assigned(res) && resource_size(res) && !pci_resource_is_optional(dev, idx)) goto out; res_name = pci_resource_name(dev, idx); add_size = add_res->add_size; align = add_res->min_align; if (!resource_assigned(res)) { resource_set_range(res, align, resource_size(res) + add_size); if (pci_assign_resource(dev, idx)) { pci_dbg(dev, "%s %pR: ignoring failure in optional allocation\n", res_name, res); } } else if (add_size > 0 || !IS_ALIGNED(res->start, align)) { res->flags |= add_res->flags & (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN); if (pci_reassign_resource(dev, idx, add_size, align)) pci_info(dev, "%s %pR: failed to add optional %llx\n", res_name, res, (unsigned long long) add_size); }out: list_del(&add_res->list); kfree(add_res); }} /** * assign_requested_resources_sorted() - Satisfy resource requests * * @head: Head of the list tracking requests for resources * @fail_head: Head of the list tracking requests that could not be * allocated * @optional: Assign also optional resources * * Satisfy resource requests of each element in the list. Add requests that * could not be satisfied to the failed_list. */static void assign_requested_resources_sorted(struct list_head *head, struct list_head *fail_head, bool optional){ struct pci_dev_resource *dev_res; struct resource *res; struct pci_dev *dev; bool optional_res; int idx; list_for_each_entry(dev_res, head, list) { res = dev_res->res; dev = dev_res->dev; idx = pci_resource_num(dev, res); optional_res = pci_resource_is_optional(dev, idx); Lines 1–500 of 2483. Load more
// SPDX-License-Identifier: GPL-2.0 /* * Support routines for initializing a PCI subsystem * * Extruded from code written by * Dave Rusling (david.rusling@reo.mts.dec.com) * David Mosberger (davidm@cs.arizona.edu) * David Miller (davem@redhat.com) * * Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru> * PCI-PCI bridges cleanup, sorted resource allocation. * Feb 2002, Ivan Kokshaysky <ink@jurassic.park.msu.ru> * Converted to allocation in 3 passes, which gives * tighter packing. Prefetchable range support. */ #include <linux/align.h> #include <linux/bitops.h> #include <linux/bug.h> #include <linux/init.h> #include <linux/kernel.h> #include <linux/minmax.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/errno.h> #include <linux/ioport.h> #include <linux/cache.h> #include <linux/limits.h> #include <linux/sizes.h> #include <linux/slab.h> #include <linux/acpi.h> #include "pci.h" #define PCI_RES_TYPE_MASK \ (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH |\ IORESOURCE_MEM_64) unsigned int pci_flags; EXPORT_SYMBOL_GPL(pci_flags); struct pci_dev_resource { struct list_head list; struct resource *res; struct pci_dev *dev; resource_size_t start; resource_size_t end; resource_size_t add_size; resource_size_t min_align; unsigned long flags; }; static void pci_dev_res_free_list(struct list_head *head) { struct pci_dev_resource *dev_res, *tmp; list_for_each_entry_safe(dev_res, tmp, head, list) { list_del(&dev_res->list); kfree(dev_res); } } /** * pci_dev_res_add_to_list() - Add a new resource tracker to the list * @head: Head of the list * @dev: Device to which the resource belongs * @res: Resource to be tracked * @add_size: Additional size to be optionally added to the resource * @min_align: Minimum memory window alignment */ int pci_dev_res_add_to_list(struct list_head *head, struct pci_dev *dev, struct resource *res, resource_size_t add_size, resource_size_t min_align) { struct pci_dev_resource *tmp; tmp = kzalloc_obj(*tmp); if (!tmp) return -ENOMEM; tmp->res = res; tmp->dev = dev; tmp->start = res->start; tmp->end = res->end; tmp->flags = res->flags; tmp->add_size = add_size; tmp->min_align = min_align; list_add(&tmp->list, head); return 0; } static void pci_dev_res_remove_from_list(struct list_head *head, struct resource *res) { struct pci_dev_resource *dev_res, *tmp; list_for_each_entry_safe(dev_res, tmp, head, list) { if (dev_res->res == res) { list_del(&dev_res->list); kfree(dev_res); break; } } } static struct pci_dev_resource *res_to_dev_res(struct list_head *head, struct resource *res) { struct pci_dev_resource *dev_res; list_for_each_entry(dev_res, head, list) { if (dev_res->res == res) return dev_res; } return NULL; } static resource_size_t get_res_add_size(struct list_head *head, struct resource *res) { struct pci_dev_resource *dev_res; dev_res = res_to_dev_res(head, res); return dev_res ? dev_res->add_size : 0; } static void pci_dev_res_restore(struct pci_dev_resource *dev_res) { struct resource *res = dev_res->res; struct pci_dev *dev = dev_res->dev; int idx = pci_resource_num(dev, res); const char *res_name = pci_resource_name(dev, idx); if (WARN_ON_ONCE(resource_assigned(res))) return; res->start = dev_res->start; res->end = dev_res->end; res->flags = dev_res->flags; pci_dbg(dev, "%s %pR: resource restored\n", res_name, res); } /* * Helper function for sizing routines. Assigned resources have non-NULL * parent resource. * * Return first unassigned resource of the correct type. If there is none, * return first assigned resource of the correct type. If none of the * above, return NULL. * * Returning an assigned resource of the correct type allows the caller to * distinguish between already assigned and no resource of the correct type. */ static struct resource *find_bus_resource_of_type(struct pci_bus *bus, unsigned long type_mask, unsigned long type) { struct resource *r, *r_assigned = NULL; pci_bus_for_each_resource(bus, r) { if (!r || r == &ioport_resource || r == &iomem_resource) continue; if ((r->flags & type_mask) != type) continue; if (!resource_assigned(r)) return r; if (!r_assigned) r_assigned = r; } return r_assigned; } /** * pbus_select_window_for_type - Select bridge window for a resource type * @bus: PCI bus * @type: Resource type (resource flags can be passed as is) * * Select the bridge window based on a resource @type. * * For memory resources, the selection is done as follows: * * Any non-prefetchable resource is put into the non-prefetchable window. * * If there is no prefetchable MMIO window, put all memory resources into the * non-prefetchable window. * * If there's a 64-bit prefetchable MMIO window, put all 64-bit prefetchable * resources into it and place 32-bit prefetchable memory into the * non-prefetchable window. * * Otherwise, put all prefetchable resources into the prefetchable window. * * Return: the bridge window resource or NULL if no bridge window is found. */ static struct resource *pbus_select_window_for_type(struct pci_bus *bus, unsigned long type) { int iores_type = type & IORESOURCE_TYPE_BITS; /* w/o 64bit & pref */ struct resource *mmio, *mmio_pref, *win; type &= PCI_RES_TYPE_MASK; /* with 64bit & pref */ if ((iores_type != IORESOURCE_IO) && (iores_type != IORESOURCE_MEM)) return NULL; if (pci_is_root_bus(bus)) { win = find_bus_resource_of_type(bus, type, type); if (win) return win; type &= ~IORESOURCE_MEM_64; win = find_bus_resource_of_type(bus, type, type); if (win) return win; type &= ~IORESOURCE_PREFETCH; return find_bus_resource_of_type(bus, type, type); } switch (iores_type) { case IORESOURCE_IO: win = pci_bus_resource_n(bus, PCI_BUS_BRIDGE_IO_WINDOW); if (win && (win->flags & IORESOURCE_IO)) return win; return NULL; case IORESOURCE_MEM: mmio = pci_bus_resource_n(bus, PCI_BUS_BRIDGE_MEM_WINDOW); mmio_pref = pci_bus_resource_n(bus, PCI_BUS_BRIDGE_PREF_MEM_WINDOW); if (mmio && !(mmio->flags & IORESOURCE_MEM)) mmio = NULL; if (mmio_pref && !(mmio_pref->flags & IORESOURCE_MEM)) mmio_pref = NULL; if (!(type & IORESOURCE_PREFETCH) || !mmio_pref) return mmio; if ((type & IORESOURCE_MEM_64) || !(mmio_pref->flags & IORESOURCE_MEM_64)) return mmio_pref; return mmio; default: return NULL; } } /** * pbus_select_window - Select bridge window for a resource * @bus: PCI bus * @res: Resource * * Select the bridge window for @res. If the resource is already assigned, * return the current bridge window. * * For memory resources, the selection is done as follows: * * Any non-prefetchable resource is put into the non-prefetchable window. * * If there is no prefetchable MMIO window, put all memory resources into the * non-prefetchable window. * * If there's a 64-bit prefetchable MMIO window, put all 64-bit prefetchable * resources into it and place 32-bit prefetchable memory into the * non-prefetchable window. * * Otherwise, put all prefetchable resources into the prefetchable window. * * Return: the bridge window resource or NULL if no bridge window is found. */ struct resource *pbus_select_window(struct pci_bus *bus, const struct resource *res) { if (resource_assigned(res)) return res->parent; return pbus_select_window_for_type(bus, res->flags); } static bool pdev_resources_assignable(struct pci_dev *dev) { u16 class = dev->class >> 8, command; /* Don't touch classless devices or host bridges or IOAPICs */ if (class == PCI_CLASS_NOT_DEFINED || class == PCI_CLASS_BRIDGE_HOST) return false; /* Don't touch IOAPIC devices already enabled by firmware */ if (class == PCI_CLASS_SYSTEM_PIC) { pci_read_config_word(dev, PCI_COMMAND, &command); if (command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY)) return false; } return true; } static bool pdev_resource_assignable(struct pci_dev *dev, struct resource *res) { int idx = pci_resource_num(dev, res); if (!res->flags) return false; if (pci_resource_is_bridge_win(idx) && res->flags & IORESOURCE_DISABLED) return false; return true; } static bool pdev_resource_should_fit(struct pci_dev *dev, struct resource *res) { if (resource_assigned(res)) return false; if (res->flags & IORESOURCE_PCI_FIXED) return false; return pdev_resource_assignable(dev, res); } /* Sort resources by alignment */ static void pdev_sort_resources(struct pci_dev *dev, struct list_head *head) { struct resource *r; int i; if (!pdev_resources_assignable(dev)) return; pci_dev_for_each_resource(dev, r, i) { const char *r_name = pci_resource_name(dev, i); struct pci_dev_resource *dev_res, *tmp; resource_size_t r_align; struct list_head *n; if (!pdev_resource_should_fit(dev, r)) continue; r_align = pci_resource_alignment(dev, r); if (!r_align) { pci_warn(dev, "%s %pR: alignment must not be zero\n", r_name, r); continue; } tmp = kzalloc_obj(*tmp); if (!tmp) panic("%s: kzalloc() failed!\n", __func__); tmp->res = r; tmp->dev = dev; tmp->start = r->start; tmp->end = r->end; tmp->flags = r->flags; /* Fallback is smallest one or list is empty */ n = head; list_for_each_entry(dev_res, head, list) { resource_size_t align; align = pci_resource_alignment(dev_res->dev, dev_res->res); if (r_align > align) { n = &dev_res->list; break; } } /* Insert it just before n */ list_add_tail(&tmp->list, n); } } bool pci_resource_is_optional(const struct pci_dev *dev, int resno) { const struct resource *res = pci_resource_n(dev, resno); if (pci_resource_is_iov(resno)) return true; if (resno == PCI_ROM_RESOURCE && !(res->flags & IORESOURCE_ROM_ENABLE)) return true; if (pci_resource_is_bridge_win(resno) && !resource_size(res)) return true; return false; } static void reset_resource(struct pci_dev *dev, struct resource *res) { int idx = pci_resource_num(dev, res); const char *res_name = pci_resource_name(dev, idx); if (pci_resource_is_bridge_win(idx)) { res->flags |= IORESOURCE_UNSET; return; } pci_dbg(dev, "%s %pR: resetting resource\n", res_name, res); res->start = 0; res->end = 0; res->flags = 0; } /** * reassign_resources_sorted() - Satisfy any additional resource requests * * @realloc_head: Head of the list tracking requests requiring * additional resources * @head: Head of the list tracking requests with allocated * resources * * Walk through each element of the realloc_head and try to procure additional * resources for the element, provided the element is in the head list. */ static void reassign_resources_sorted(struct list_head *realloc_head, struct list_head *head) { struct pci_dev_resource *add_res, *tmp; struct pci_dev *dev; struct resource *res; const char *res_name; resource_size_t add_size, align; int idx; list_for_each_entry_safe(add_res, tmp, realloc_head, list) { res = add_res->res; dev = add_res->dev; idx = pci_resource_num(dev, res); /* Skip this resource if not found in head list */ if (!res_to_dev_res(head, res)) continue; /* * Skip resource that failed the earlier assignment and is * not optional as it would just fail again. */ if (!resource_assigned(res) && resource_size(res) && !pci_resource_is_optional(dev, idx)) goto out; res_name = pci_resource_name(dev, idx); add_size = add_res->add_size; align = add_res->min_align; if (!resource_assigned(res)) { resource_set_range(res, align, resource_size(res) + add_size); if (pci_assign_resource(dev, idx)) { pci_dbg(dev, "%s %pR: ignoring failure in optional allocation\n", res_name, res); } } else if (add_size > 0 || !IS_ALIGNED(res->start, align)) { res->flags |= add_res->flags & (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN); if (pci_reassign_resource(dev, idx, add_size, align)) pci_info(dev, "%s %pR: failed to add optional %llx\n", res_name, res, (unsigned long long) add_size); } out: list_del(&add_res->list); kfree(add_res); } } /** * assign_requested_resources_sorted() - Satisfy resource requests * * @head: Head of the list tracking requests for resources * @fail_head: Head of the list tracking requests that could not be * allocated * @optional: Assign also optional resources * * Satisfy resource requests of each element in the list. Add requests that * could not be satisfied to the failed_list. */ static void assign_requested_resources_sorted(struct list_head *head, struct list_head *fail_head, bool optional) { struct pci_dev_resource *dev_res; struct resource *res; struct pci_dev *dev; bool optional_res; int idx; list_for_each_entry(dev_res, head, list) { res = dev_res->res; dev = dev_res->dev; idx = pci_resource_num(dev, res); optional_res = pci_resource_is_optional(dev, idx);