18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Support routines for initializing a PCI subsystem
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Extruded from code written by
68c2ecf20Sopenharmony_ci *      Dave Rusling (david.rusling@reo.mts.dec.com)
78c2ecf20Sopenharmony_ci *      David Mosberger (davidm@cs.arizona.edu)
88c2ecf20Sopenharmony_ci *	David Miller (davem@redhat.com)
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci * Nov 2000, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
118c2ecf20Sopenharmony_ci *	     PCI-PCI bridges cleanup, sorted resource allocation.
128c2ecf20Sopenharmony_ci * Feb 2002, Ivan Kokshaysky <ink@jurassic.park.msu.ru>
138c2ecf20Sopenharmony_ci *	     Converted to allocation in 3 passes, which gives
148c2ecf20Sopenharmony_ci *	     tighter packing. Prefetchable range support.
158c2ecf20Sopenharmony_ci */
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci#include <linux/init.h>
188c2ecf20Sopenharmony_ci#include <linux/kernel.h>
198c2ecf20Sopenharmony_ci#include <linux/module.h>
208c2ecf20Sopenharmony_ci#include <linux/pci.h>
218c2ecf20Sopenharmony_ci#include <linux/errno.h>
228c2ecf20Sopenharmony_ci#include <linux/ioport.h>
238c2ecf20Sopenharmony_ci#include <linux/cache.h>
248c2ecf20Sopenharmony_ci#include <linux/slab.h>
258c2ecf20Sopenharmony_ci#include <linux/acpi.h>
268c2ecf20Sopenharmony_ci#include "pci.h"
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ciunsigned int pci_flags;
298c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_flags);
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_cistruct pci_dev_resource {
328c2ecf20Sopenharmony_ci	struct list_head list;
338c2ecf20Sopenharmony_ci	struct resource *res;
348c2ecf20Sopenharmony_ci	struct pci_dev *dev;
358c2ecf20Sopenharmony_ci	resource_size_t start;
368c2ecf20Sopenharmony_ci	resource_size_t end;
378c2ecf20Sopenharmony_ci	resource_size_t add_size;
388c2ecf20Sopenharmony_ci	resource_size_t min_align;
398c2ecf20Sopenharmony_ci	unsigned long flags;
408c2ecf20Sopenharmony_ci};
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic void free_list(struct list_head *head)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	struct pci_dev_resource *dev_res, *tmp;
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	list_for_each_entry_safe(dev_res, tmp, head, list) {
478c2ecf20Sopenharmony_ci		list_del(&dev_res->list);
488c2ecf20Sopenharmony_ci		kfree(dev_res);
498c2ecf20Sopenharmony_ci	}
508c2ecf20Sopenharmony_ci}
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci/**
538c2ecf20Sopenharmony_ci * add_to_list() - Add a new resource tracker to the list
548c2ecf20Sopenharmony_ci * @head:	Head of the list
558c2ecf20Sopenharmony_ci * @dev:	Device to which the resource belongs
568c2ecf20Sopenharmony_ci * @res:	Resource to be tracked
578c2ecf20Sopenharmony_ci * @add_size:	Additional size to be optionally added to the resource
588c2ecf20Sopenharmony_ci * @min_align:	Minimum memory window alignment
598c2ecf20Sopenharmony_ci */
608c2ecf20Sopenharmony_cistatic int add_to_list(struct list_head *head, struct pci_dev *dev,
618c2ecf20Sopenharmony_ci		       struct resource *res, resource_size_t add_size,
628c2ecf20Sopenharmony_ci		       resource_size_t min_align)
638c2ecf20Sopenharmony_ci{
648c2ecf20Sopenharmony_ci	struct pci_dev_resource *tmp;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
678c2ecf20Sopenharmony_ci	if (!tmp)
688c2ecf20Sopenharmony_ci		return -ENOMEM;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	tmp->res = res;
718c2ecf20Sopenharmony_ci	tmp->dev = dev;
728c2ecf20Sopenharmony_ci	tmp->start = res->start;
738c2ecf20Sopenharmony_ci	tmp->end = res->end;
748c2ecf20Sopenharmony_ci	tmp->flags = res->flags;
758c2ecf20Sopenharmony_ci	tmp->add_size = add_size;
768c2ecf20Sopenharmony_ci	tmp->min_align = min_align;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	list_add(&tmp->list, head);
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci	return 0;
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic void remove_from_list(struct list_head *head, struct resource *res)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	struct pci_dev_resource *dev_res, *tmp;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	list_for_each_entry_safe(dev_res, tmp, head, list) {
888c2ecf20Sopenharmony_ci		if (dev_res->res == res) {
898c2ecf20Sopenharmony_ci			list_del(&dev_res->list);
908c2ecf20Sopenharmony_ci			kfree(dev_res);
918c2ecf20Sopenharmony_ci			break;
928c2ecf20Sopenharmony_ci		}
938c2ecf20Sopenharmony_ci	}
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_cistatic struct pci_dev_resource *res_to_dev_res(struct list_head *head,
978c2ecf20Sopenharmony_ci					       struct resource *res)
988c2ecf20Sopenharmony_ci{
998c2ecf20Sopenharmony_ci	struct pci_dev_resource *dev_res;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	list_for_each_entry(dev_res, head, list) {
1028c2ecf20Sopenharmony_ci		if (dev_res->res == res)
1038c2ecf20Sopenharmony_ci			return dev_res;
1048c2ecf20Sopenharmony_ci	}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	return NULL;
1078c2ecf20Sopenharmony_ci}
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_cistatic resource_size_t get_res_add_size(struct list_head *head,
1108c2ecf20Sopenharmony_ci					struct resource *res)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	struct pci_dev_resource *dev_res;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	dev_res = res_to_dev_res(head, res);
1158c2ecf20Sopenharmony_ci	return dev_res ? dev_res->add_size : 0;
1168c2ecf20Sopenharmony_ci}
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic resource_size_t get_res_add_align(struct list_head *head,
1198c2ecf20Sopenharmony_ci					 struct resource *res)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	struct pci_dev_resource *dev_res;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci	dev_res = res_to_dev_res(head, res);
1248c2ecf20Sopenharmony_ci	return dev_res ? dev_res->min_align : 0;
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci/* Sort resources by alignment */
1298c2ecf20Sopenharmony_cistatic void pdev_sort_resources(struct pci_dev *dev, struct list_head *head)
1308c2ecf20Sopenharmony_ci{
1318c2ecf20Sopenharmony_ci	int i;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
1348c2ecf20Sopenharmony_ci		struct resource *r;
1358c2ecf20Sopenharmony_ci		struct pci_dev_resource *dev_res, *tmp;
1368c2ecf20Sopenharmony_ci		resource_size_t r_align;
1378c2ecf20Sopenharmony_ci		struct list_head *n;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci		r = &dev->resource[i];
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci		if (r->flags & IORESOURCE_PCI_FIXED)
1428c2ecf20Sopenharmony_ci			continue;
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci		if (!(r->flags) || r->parent)
1458c2ecf20Sopenharmony_ci			continue;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci		r_align = pci_resource_alignment(dev, r);
1488c2ecf20Sopenharmony_ci		if (!r_align) {
1498c2ecf20Sopenharmony_ci			pci_warn(dev, "BAR %d: %pR has bogus alignment\n",
1508c2ecf20Sopenharmony_ci				 i, r);
1518c2ecf20Sopenharmony_ci			continue;
1528c2ecf20Sopenharmony_ci		}
1538c2ecf20Sopenharmony_ci
1548c2ecf20Sopenharmony_ci		tmp = kzalloc(sizeof(*tmp), GFP_KERNEL);
1558c2ecf20Sopenharmony_ci		if (!tmp)
1568c2ecf20Sopenharmony_ci			panic("%s: kzalloc() failed!\n", __func__);
1578c2ecf20Sopenharmony_ci		tmp->res = r;
1588c2ecf20Sopenharmony_ci		tmp->dev = dev;
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci		/* Fallback is smallest one or list is empty */
1618c2ecf20Sopenharmony_ci		n = head;
1628c2ecf20Sopenharmony_ci		list_for_each_entry(dev_res, head, list) {
1638c2ecf20Sopenharmony_ci			resource_size_t align;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci			align = pci_resource_alignment(dev_res->dev,
1668c2ecf20Sopenharmony_ci							 dev_res->res);
1678c2ecf20Sopenharmony_ci
1688c2ecf20Sopenharmony_ci			if (r_align > align) {
1698c2ecf20Sopenharmony_ci				n = &dev_res->list;
1708c2ecf20Sopenharmony_ci				break;
1718c2ecf20Sopenharmony_ci			}
1728c2ecf20Sopenharmony_ci		}
1738c2ecf20Sopenharmony_ci		/* Insert it just before n */
1748c2ecf20Sopenharmony_ci		list_add_tail(&tmp->list, n);
1758c2ecf20Sopenharmony_ci	}
1768c2ecf20Sopenharmony_ci}
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic void __dev_sort_resources(struct pci_dev *dev, struct list_head *head)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	u16 class = dev->class >> 8;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci	/* Don't touch classless devices or host bridges or IOAPICs */
1838c2ecf20Sopenharmony_ci	if (class == PCI_CLASS_NOT_DEFINED || class == PCI_CLASS_BRIDGE_HOST)
1848c2ecf20Sopenharmony_ci		return;
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	/* Don't touch IOAPIC devices already enabled by firmware */
1878c2ecf20Sopenharmony_ci	if (class == PCI_CLASS_SYSTEM_PIC) {
1888c2ecf20Sopenharmony_ci		u16 command;
1898c2ecf20Sopenharmony_ci		pci_read_config_word(dev, PCI_COMMAND, &command);
1908c2ecf20Sopenharmony_ci		if (command & (PCI_COMMAND_IO | PCI_COMMAND_MEMORY))
1918c2ecf20Sopenharmony_ci			return;
1928c2ecf20Sopenharmony_ci	}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	pdev_sort_resources(dev, head);
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic inline void reset_resource(struct resource *res)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	res->start = 0;
2008c2ecf20Sopenharmony_ci	res->end = 0;
2018c2ecf20Sopenharmony_ci	res->flags = 0;
2028c2ecf20Sopenharmony_ci}
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci/**
2058c2ecf20Sopenharmony_ci * reassign_resources_sorted() - Satisfy any additional resource requests
2068c2ecf20Sopenharmony_ci *
2078c2ecf20Sopenharmony_ci * @realloc_head:	Head of the list tracking requests requiring
2088c2ecf20Sopenharmony_ci *			additional resources
2098c2ecf20Sopenharmony_ci * @head:		Head of the list tracking requests with allocated
2108c2ecf20Sopenharmony_ci *			resources
2118c2ecf20Sopenharmony_ci *
2128c2ecf20Sopenharmony_ci * Walk through each element of the realloc_head and try to procure additional
2138c2ecf20Sopenharmony_ci * resources for the element, provided the element is in the head list.
2148c2ecf20Sopenharmony_ci */
2158c2ecf20Sopenharmony_cistatic void reassign_resources_sorted(struct list_head *realloc_head,
2168c2ecf20Sopenharmony_ci				      struct list_head *head)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	struct resource *res;
2198c2ecf20Sopenharmony_ci	struct pci_dev_resource *add_res, *tmp;
2208c2ecf20Sopenharmony_ci	struct pci_dev_resource *dev_res;
2218c2ecf20Sopenharmony_ci	resource_size_t add_size, align;
2228c2ecf20Sopenharmony_ci	int idx;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	list_for_each_entry_safe(add_res, tmp, realloc_head, list) {
2258c2ecf20Sopenharmony_ci		bool found_match = false;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci		res = add_res->res;
2288c2ecf20Sopenharmony_ci		/* Skip resource that has been reset */
2298c2ecf20Sopenharmony_ci		if (!res->flags)
2308c2ecf20Sopenharmony_ci			goto out;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci		/* Skip this resource if not found in head list */
2338c2ecf20Sopenharmony_ci		list_for_each_entry(dev_res, head, list) {
2348c2ecf20Sopenharmony_ci			if (dev_res->res == res) {
2358c2ecf20Sopenharmony_ci				found_match = true;
2368c2ecf20Sopenharmony_ci				break;
2378c2ecf20Sopenharmony_ci			}
2388c2ecf20Sopenharmony_ci		}
2398c2ecf20Sopenharmony_ci		if (!found_match) /* Just skip */
2408c2ecf20Sopenharmony_ci			continue;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci		idx = res - &add_res->dev->resource[0];
2438c2ecf20Sopenharmony_ci		add_size = add_res->add_size;
2448c2ecf20Sopenharmony_ci		align = add_res->min_align;
2458c2ecf20Sopenharmony_ci		if (!resource_size(res)) {
2468c2ecf20Sopenharmony_ci			res->start = align;
2478c2ecf20Sopenharmony_ci			res->end = res->start + add_size - 1;
2488c2ecf20Sopenharmony_ci			if (pci_assign_resource(add_res->dev, idx))
2498c2ecf20Sopenharmony_ci				reset_resource(res);
2508c2ecf20Sopenharmony_ci		} else {
2518c2ecf20Sopenharmony_ci			res->flags |= add_res->flags &
2528c2ecf20Sopenharmony_ci				 (IORESOURCE_STARTALIGN|IORESOURCE_SIZEALIGN);
2538c2ecf20Sopenharmony_ci			if (pci_reassign_resource(add_res->dev, idx,
2548c2ecf20Sopenharmony_ci						  add_size, align))
2558c2ecf20Sopenharmony_ci				pci_info(add_res->dev, "failed to add %llx res[%d]=%pR\n",
2568c2ecf20Sopenharmony_ci					 (unsigned long long) add_size, idx,
2578c2ecf20Sopenharmony_ci					 res);
2588c2ecf20Sopenharmony_ci		}
2598c2ecf20Sopenharmony_ciout:
2608c2ecf20Sopenharmony_ci		list_del(&add_res->list);
2618c2ecf20Sopenharmony_ci		kfree(add_res);
2628c2ecf20Sopenharmony_ci	}
2638c2ecf20Sopenharmony_ci}
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci/**
2668c2ecf20Sopenharmony_ci * assign_requested_resources_sorted() - Satisfy resource requests
2678c2ecf20Sopenharmony_ci *
2688c2ecf20Sopenharmony_ci * @head:	Head of the list tracking requests for resources
2698c2ecf20Sopenharmony_ci * @fail_head:	Head of the list tracking requests that could not be
2708c2ecf20Sopenharmony_ci *		allocated
2718c2ecf20Sopenharmony_ci *
2728c2ecf20Sopenharmony_ci * Satisfy resource requests of each element in the list.  Add requests that
2738c2ecf20Sopenharmony_ci * could not be satisfied to the failed_list.
2748c2ecf20Sopenharmony_ci */
2758c2ecf20Sopenharmony_cistatic void assign_requested_resources_sorted(struct list_head *head,
2768c2ecf20Sopenharmony_ci				 struct list_head *fail_head)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	struct resource *res;
2798c2ecf20Sopenharmony_ci	struct pci_dev_resource *dev_res;
2808c2ecf20Sopenharmony_ci	int idx;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	list_for_each_entry(dev_res, head, list) {
2838c2ecf20Sopenharmony_ci		res = dev_res->res;
2848c2ecf20Sopenharmony_ci		idx = res - &dev_res->dev->resource[0];
2858c2ecf20Sopenharmony_ci		if (resource_size(res) &&
2868c2ecf20Sopenharmony_ci		    pci_assign_resource(dev_res->dev, idx)) {
2878c2ecf20Sopenharmony_ci			if (fail_head) {
2888c2ecf20Sopenharmony_ci				/*
2898c2ecf20Sopenharmony_ci				 * If the failed resource is a ROM BAR and
2908c2ecf20Sopenharmony_ci				 * it will be enabled later, don't add it
2918c2ecf20Sopenharmony_ci				 * to the list.
2928c2ecf20Sopenharmony_ci				 */
2938c2ecf20Sopenharmony_ci				if (!((idx == PCI_ROM_RESOURCE) &&
2948c2ecf20Sopenharmony_ci				      (!(res->flags & IORESOURCE_ROM_ENABLE))))
2958c2ecf20Sopenharmony_ci					add_to_list(fail_head,
2968c2ecf20Sopenharmony_ci						    dev_res->dev, res,
2978c2ecf20Sopenharmony_ci						    0 /* don't care */,
2988c2ecf20Sopenharmony_ci						    0 /* don't care */);
2998c2ecf20Sopenharmony_ci			}
3008c2ecf20Sopenharmony_ci			reset_resource(res);
3018c2ecf20Sopenharmony_ci		}
3028c2ecf20Sopenharmony_ci	}
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_cistatic unsigned long pci_fail_res_type_mask(struct list_head *fail_head)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	struct pci_dev_resource *fail_res;
3088c2ecf20Sopenharmony_ci	unsigned long mask = 0;
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci	/* Check failed type */
3118c2ecf20Sopenharmony_ci	list_for_each_entry(fail_res, fail_head, list)
3128c2ecf20Sopenharmony_ci		mask |= fail_res->flags;
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	/*
3158c2ecf20Sopenharmony_ci	 * One pref failed resource will set IORESOURCE_MEM, as we can
3168c2ecf20Sopenharmony_ci	 * allocate pref in non-pref range.  Will release all assigned
3178c2ecf20Sopenharmony_ci	 * non-pref sibling resources according to that bit.
3188c2ecf20Sopenharmony_ci	 */
3198c2ecf20Sopenharmony_ci	return mask & (IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH);
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_cistatic bool pci_need_to_release(unsigned long mask, struct resource *res)
3238c2ecf20Sopenharmony_ci{
3248c2ecf20Sopenharmony_ci	if (res->flags & IORESOURCE_IO)
3258c2ecf20Sopenharmony_ci		return !!(mask & IORESOURCE_IO);
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	/* Check pref at first */
3288c2ecf20Sopenharmony_ci	if (res->flags & IORESOURCE_PREFETCH) {
3298c2ecf20Sopenharmony_ci		if (mask & IORESOURCE_PREFETCH)
3308c2ecf20Sopenharmony_ci			return true;
3318c2ecf20Sopenharmony_ci		/* Count pref if its parent is non-pref */
3328c2ecf20Sopenharmony_ci		else if ((mask & IORESOURCE_MEM) &&
3338c2ecf20Sopenharmony_ci			 !(res->parent->flags & IORESOURCE_PREFETCH))
3348c2ecf20Sopenharmony_ci			return true;
3358c2ecf20Sopenharmony_ci		else
3368c2ecf20Sopenharmony_ci			return false;
3378c2ecf20Sopenharmony_ci	}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (res->flags & IORESOURCE_MEM)
3408c2ecf20Sopenharmony_ci		return !!(mask & IORESOURCE_MEM);
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_ci	return false;	/* Should not get here */
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cistatic void __assign_resources_sorted(struct list_head *head,
3468c2ecf20Sopenharmony_ci				      struct list_head *realloc_head,
3478c2ecf20Sopenharmony_ci				      struct list_head *fail_head)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	/*
3508c2ecf20Sopenharmony_ci	 * Should not assign requested resources at first.  They could be
3518c2ecf20Sopenharmony_ci	 * adjacent, so later reassign can not reallocate them one by one in
3528c2ecf20Sopenharmony_ci	 * parent resource window.
3538c2ecf20Sopenharmony_ci	 *
3548c2ecf20Sopenharmony_ci	 * Try to assign requested + add_size at beginning.  If could do that,
3558c2ecf20Sopenharmony_ci	 * could get out early.  If could not do that, we still try to assign
3568c2ecf20Sopenharmony_ci	 * requested at first, then try to reassign add_size for some resources.
3578c2ecf20Sopenharmony_ci	 *
3588c2ecf20Sopenharmony_ci	 * Separate three resource type checking if we need to release
3598c2ecf20Sopenharmony_ci	 * assigned resource after requested + add_size try.
3608c2ecf20Sopenharmony_ci	 *
3618c2ecf20Sopenharmony_ci	 *	1. If IO port assignment fails, will release assigned IO
3628c2ecf20Sopenharmony_ci	 *	   port.
3638c2ecf20Sopenharmony_ci	 *	2. If pref MMIO assignment fails, release assigned pref
3648c2ecf20Sopenharmony_ci	 *	   MMIO.  If assigned pref MMIO's parent is non-pref MMIO
3658c2ecf20Sopenharmony_ci	 *	   and non-pref MMIO assignment fails, will release that
3668c2ecf20Sopenharmony_ci	 *	   assigned pref MMIO.
3678c2ecf20Sopenharmony_ci	 *	3. If non-pref MMIO assignment fails or pref MMIO
3688c2ecf20Sopenharmony_ci	 *	   assignment fails, will release assigned non-pref MMIO.
3698c2ecf20Sopenharmony_ci	 */
3708c2ecf20Sopenharmony_ci	LIST_HEAD(save_head);
3718c2ecf20Sopenharmony_ci	LIST_HEAD(local_fail_head);
3728c2ecf20Sopenharmony_ci	struct pci_dev_resource *save_res;
3738c2ecf20Sopenharmony_ci	struct pci_dev_resource *dev_res, *tmp_res, *dev_res2;
3748c2ecf20Sopenharmony_ci	unsigned long fail_type;
3758c2ecf20Sopenharmony_ci	resource_size_t add_align, align;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	/* Check if optional add_size is there */
3788c2ecf20Sopenharmony_ci	if (!realloc_head || list_empty(realloc_head))
3798c2ecf20Sopenharmony_ci		goto requested_and_reassign;
3808c2ecf20Sopenharmony_ci
3818c2ecf20Sopenharmony_ci	/* Save original start, end, flags etc at first */
3828c2ecf20Sopenharmony_ci	list_for_each_entry(dev_res, head, list) {
3838c2ecf20Sopenharmony_ci		if (add_to_list(&save_head, dev_res->dev, dev_res->res, 0, 0)) {
3848c2ecf20Sopenharmony_ci			free_list(&save_head);
3858c2ecf20Sopenharmony_ci			goto requested_and_reassign;
3868c2ecf20Sopenharmony_ci		}
3878c2ecf20Sopenharmony_ci	}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci	/* Update res in head list with add_size in realloc_head list */
3908c2ecf20Sopenharmony_ci	list_for_each_entry_safe(dev_res, tmp_res, head, list) {
3918c2ecf20Sopenharmony_ci		dev_res->res->end += get_res_add_size(realloc_head,
3928c2ecf20Sopenharmony_ci							dev_res->res);
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci		/*
3958c2ecf20Sopenharmony_ci		 * There are two kinds of additional resources in the list:
3968c2ecf20Sopenharmony_ci		 * 1. bridge resource  -- IORESOURCE_STARTALIGN
3978c2ecf20Sopenharmony_ci		 * 2. SR-IOV resource  -- IORESOURCE_SIZEALIGN
3988c2ecf20Sopenharmony_ci		 * Here just fix the additional alignment for bridge
3998c2ecf20Sopenharmony_ci		 */
4008c2ecf20Sopenharmony_ci		if (!(dev_res->res->flags & IORESOURCE_STARTALIGN))
4018c2ecf20Sopenharmony_ci			continue;
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci		add_align = get_res_add_align(realloc_head, dev_res->res);
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci		/*
4068c2ecf20Sopenharmony_ci		 * The "head" list is sorted by alignment so resources with
4078c2ecf20Sopenharmony_ci		 * bigger alignment will be assigned first.  After we
4088c2ecf20Sopenharmony_ci		 * change the alignment of a dev_res in "head" list, we
4098c2ecf20Sopenharmony_ci		 * need to reorder the list by alignment to make it
4108c2ecf20Sopenharmony_ci		 * consistent.
4118c2ecf20Sopenharmony_ci		 */
4128c2ecf20Sopenharmony_ci		if (add_align > dev_res->res->start) {
4138c2ecf20Sopenharmony_ci			resource_size_t r_size = resource_size(dev_res->res);
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_ci			dev_res->res->start = add_align;
4168c2ecf20Sopenharmony_ci			dev_res->res->end = add_align + r_size - 1;
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci			list_for_each_entry(dev_res2, head, list) {
4198c2ecf20Sopenharmony_ci				align = pci_resource_alignment(dev_res2->dev,
4208c2ecf20Sopenharmony_ci							       dev_res2->res);
4218c2ecf20Sopenharmony_ci				if (add_align > align) {
4228c2ecf20Sopenharmony_ci					list_move_tail(&dev_res->list,
4238c2ecf20Sopenharmony_ci						       &dev_res2->list);
4248c2ecf20Sopenharmony_ci					break;
4258c2ecf20Sopenharmony_ci				}
4268c2ecf20Sopenharmony_ci			}
4278c2ecf20Sopenharmony_ci		}
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci	/* Try updated head list with add_size added */
4328c2ecf20Sopenharmony_ci	assign_requested_resources_sorted(head, &local_fail_head);
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	/* All assigned with add_size? */
4358c2ecf20Sopenharmony_ci	if (list_empty(&local_fail_head)) {
4368c2ecf20Sopenharmony_ci		/* Remove head list from realloc_head list */
4378c2ecf20Sopenharmony_ci		list_for_each_entry(dev_res, head, list)
4388c2ecf20Sopenharmony_ci			remove_from_list(realloc_head, dev_res->res);
4398c2ecf20Sopenharmony_ci		free_list(&save_head);
4408c2ecf20Sopenharmony_ci		free_list(head);
4418c2ecf20Sopenharmony_ci		return;
4428c2ecf20Sopenharmony_ci	}
4438c2ecf20Sopenharmony_ci
4448c2ecf20Sopenharmony_ci	/* Check failed type */
4458c2ecf20Sopenharmony_ci	fail_type = pci_fail_res_type_mask(&local_fail_head);
4468c2ecf20Sopenharmony_ci	/* Remove not need to be released assigned res from head list etc */
4478c2ecf20Sopenharmony_ci	list_for_each_entry_safe(dev_res, tmp_res, head, list)
4488c2ecf20Sopenharmony_ci		if (dev_res->res->parent &&
4498c2ecf20Sopenharmony_ci		    !pci_need_to_release(fail_type, dev_res->res)) {
4508c2ecf20Sopenharmony_ci			/* Remove it from realloc_head list */
4518c2ecf20Sopenharmony_ci			remove_from_list(realloc_head, dev_res->res);
4528c2ecf20Sopenharmony_ci			remove_from_list(&save_head, dev_res->res);
4538c2ecf20Sopenharmony_ci			list_del(&dev_res->list);
4548c2ecf20Sopenharmony_ci			kfree(dev_res);
4558c2ecf20Sopenharmony_ci		}
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	free_list(&local_fail_head);
4588c2ecf20Sopenharmony_ci	/* Release assigned resource */
4598c2ecf20Sopenharmony_ci	list_for_each_entry(dev_res, head, list)
4608c2ecf20Sopenharmony_ci		if (dev_res->res->parent)
4618c2ecf20Sopenharmony_ci			release_resource(dev_res->res);
4628c2ecf20Sopenharmony_ci	/* Restore start/end/flags from saved list */
4638c2ecf20Sopenharmony_ci	list_for_each_entry(save_res, &save_head, list) {
4648c2ecf20Sopenharmony_ci		struct resource *res = save_res->res;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci		res->start = save_res->start;
4678c2ecf20Sopenharmony_ci		res->end = save_res->end;
4688c2ecf20Sopenharmony_ci		res->flags = save_res->flags;
4698c2ecf20Sopenharmony_ci	}
4708c2ecf20Sopenharmony_ci	free_list(&save_head);
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_cirequested_and_reassign:
4738c2ecf20Sopenharmony_ci	/* Satisfy the must-have resource requests */
4748c2ecf20Sopenharmony_ci	assign_requested_resources_sorted(head, fail_head);
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	/* Try to satisfy any additional optional resource requests */
4778c2ecf20Sopenharmony_ci	if (realloc_head)
4788c2ecf20Sopenharmony_ci		reassign_resources_sorted(realloc_head, head);
4798c2ecf20Sopenharmony_ci	free_list(head);
4808c2ecf20Sopenharmony_ci}
4818c2ecf20Sopenharmony_ci
4828c2ecf20Sopenharmony_cistatic void pdev_assign_resources_sorted(struct pci_dev *dev,
4838c2ecf20Sopenharmony_ci					 struct list_head *add_head,
4848c2ecf20Sopenharmony_ci					 struct list_head *fail_head)
4858c2ecf20Sopenharmony_ci{
4868c2ecf20Sopenharmony_ci	LIST_HEAD(head);
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	__dev_sort_resources(dev, &head);
4898c2ecf20Sopenharmony_ci	__assign_resources_sorted(&head, add_head, fail_head);
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_cistatic void pbus_assign_resources_sorted(const struct pci_bus *bus,
4948c2ecf20Sopenharmony_ci					 struct list_head *realloc_head,
4958c2ecf20Sopenharmony_ci					 struct list_head *fail_head)
4968c2ecf20Sopenharmony_ci{
4978c2ecf20Sopenharmony_ci	struct pci_dev *dev;
4988c2ecf20Sopenharmony_ci	LIST_HEAD(head);
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &bus->devices, bus_list)
5018c2ecf20Sopenharmony_ci		__dev_sort_resources(dev, &head);
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	__assign_resources_sorted(&head, realloc_head, fail_head);
5048c2ecf20Sopenharmony_ci}
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_civoid pci_setup_cardbus(struct pci_bus *bus)
5078c2ecf20Sopenharmony_ci{
5088c2ecf20Sopenharmony_ci	struct pci_dev *bridge = bus->self;
5098c2ecf20Sopenharmony_ci	struct resource *res;
5108c2ecf20Sopenharmony_ci	struct pci_bus_region region;
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_ci	pci_info(bridge, "CardBus bridge to %pR\n",
5138c2ecf20Sopenharmony_ci		 &bus->busn_res);
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	res = bus->resource[0];
5168c2ecf20Sopenharmony_ci	pcibios_resource_to_bus(bridge->bus, &region, res);
5178c2ecf20Sopenharmony_ci	if (res->flags & IORESOURCE_IO) {
5188c2ecf20Sopenharmony_ci		/*
5198c2ecf20Sopenharmony_ci		 * The IO resource is allocated a range twice as large as it
5208c2ecf20Sopenharmony_ci		 * would normally need.  This allows us to set both IO regs.
5218c2ecf20Sopenharmony_ci		 */
5228c2ecf20Sopenharmony_ci		pci_info(bridge, "  bridge window %pR\n", res);
5238c2ecf20Sopenharmony_ci		pci_write_config_dword(bridge, PCI_CB_IO_BASE_0,
5248c2ecf20Sopenharmony_ci					region.start);
5258c2ecf20Sopenharmony_ci		pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0,
5268c2ecf20Sopenharmony_ci					region.end);
5278c2ecf20Sopenharmony_ci	}
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	res = bus->resource[1];
5308c2ecf20Sopenharmony_ci	pcibios_resource_to_bus(bridge->bus, &region, res);
5318c2ecf20Sopenharmony_ci	if (res->flags & IORESOURCE_IO) {
5328c2ecf20Sopenharmony_ci		pci_info(bridge, "  bridge window %pR\n", res);
5338c2ecf20Sopenharmony_ci		pci_write_config_dword(bridge, PCI_CB_IO_BASE_1,
5348c2ecf20Sopenharmony_ci					region.start);
5358c2ecf20Sopenharmony_ci		pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1,
5368c2ecf20Sopenharmony_ci					region.end);
5378c2ecf20Sopenharmony_ci	}
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	res = bus->resource[2];
5408c2ecf20Sopenharmony_ci	pcibios_resource_to_bus(bridge->bus, &region, res);
5418c2ecf20Sopenharmony_ci	if (res->flags & IORESOURCE_MEM) {
5428c2ecf20Sopenharmony_ci		pci_info(bridge, "  bridge window %pR\n", res);
5438c2ecf20Sopenharmony_ci		pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0,
5448c2ecf20Sopenharmony_ci					region.start);
5458c2ecf20Sopenharmony_ci		pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0,
5468c2ecf20Sopenharmony_ci					region.end);
5478c2ecf20Sopenharmony_ci	}
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	res = bus->resource[3];
5508c2ecf20Sopenharmony_ci	pcibios_resource_to_bus(bridge->bus, &region, res);
5518c2ecf20Sopenharmony_ci	if (res->flags & IORESOURCE_MEM) {
5528c2ecf20Sopenharmony_ci		pci_info(bridge, "  bridge window %pR\n", res);
5538c2ecf20Sopenharmony_ci		pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1,
5548c2ecf20Sopenharmony_ci					region.start);
5558c2ecf20Sopenharmony_ci		pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1,
5568c2ecf20Sopenharmony_ci					region.end);
5578c2ecf20Sopenharmony_ci	}
5588c2ecf20Sopenharmony_ci}
5598c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_setup_cardbus);
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci/*
5628c2ecf20Sopenharmony_ci * Initialize bridges with base/limit values we have collected.  PCI-to-PCI
5638c2ecf20Sopenharmony_ci * Bridge Architecture Specification rev. 1.1 (1998) requires that if there
5648c2ecf20Sopenharmony_ci * are no I/O ports or memory behind the bridge, the corresponding range
5658c2ecf20Sopenharmony_ci * must be turned off by writing base value greater than limit to the
5668c2ecf20Sopenharmony_ci * bridge's base/limit registers.
5678c2ecf20Sopenharmony_ci *
5688c2ecf20Sopenharmony_ci * Note: care must be taken when updating I/O base/limit registers of
5698c2ecf20Sopenharmony_ci * bridges which support 32-bit I/O.  This update requires two config space
5708c2ecf20Sopenharmony_ci * writes, so it's quite possible that an I/O window of the bridge will
5718c2ecf20Sopenharmony_ci * have some undesirable address (e.g. 0) after the first write.  Ditto
5728c2ecf20Sopenharmony_ci * 64-bit prefetchable MMIO.
5738c2ecf20Sopenharmony_ci */
5748c2ecf20Sopenharmony_cistatic void pci_setup_bridge_io(struct pci_dev *bridge)
5758c2ecf20Sopenharmony_ci{
5768c2ecf20Sopenharmony_ci	struct resource *res;
5778c2ecf20Sopenharmony_ci	struct pci_bus_region region;
5788c2ecf20Sopenharmony_ci	unsigned long io_mask;
5798c2ecf20Sopenharmony_ci	u8 io_base_lo, io_limit_lo;
5808c2ecf20Sopenharmony_ci	u16 l;
5818c2ecf20Sopenharmony_ci	u32 io_upper16;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	io_mask = PCI_IO_RANGE_MASK;
5848c2ecf20Sopenharmony_ci	if (bridge->io_window_1k)
5858c2ecf20Sopenharmony_ci		io_mask = PCI_IO_1K_RANGE_MASK;
5868c2ecf20Sopenharmony_ci
5878c2ecf20Sopenharmony_ci	/* Set up the top and bottom of the PCI I/O segment for this bus */
5888c2ecf20Sopenharmony_ci	res = &bridge->resource[PCI_BRIDGE_IO_WINDOW];
5898c2ecf20Sopenharmony_ci	pcibios_resource_to_bus(bridge->bus, &region, res);
5908c2ecf20Sopenharmony_ci	if (res->flags & IORESOURCE_IO) {
5918c2ecf20Sopenharmony_ci		pci_read_config_word(bridge, PCI_IO_BASE, &l);
5928c2ecf20Sopenharmony_ci		io_base_lo = (region.start >> 8) & io_mask;
5938c2ecf20Sopenharmony_ci		io_limit_lo = (region.end >> 8) & io_mask;
5948c2ecf20Sopenharmony_ci		l = ((u16) io_limit_lo << 8) | io_base_lo;
5958c2ecf20Sopenharmony_ci		/* Set up upper 16 bits of I/O base/limit */
5968c2ecf20Sopenharmony_ci		io_upper16 = (region.end & 0xffff0000) | (region.start >> 16);
5978c2ecf20Sopenharmony_ci		pci_info(bridge, "  bridge window %pR\n", res);
5988c2ecf20Sopenharmony_ci	} else {
5998c2ecf20Sopenharmony_ci		/* Clear upper 16 bits of I/O base/limit */
6008c2ecf20Sopenharmony_ci		io_upper16 = 0;
6018c2ecf20Sopenharmony_ci		l = 0x00f0;
6028c2ecf20Sopenharmony_ci	}
6038c2ecf20Sopenharmony_ci	/* Temporarily disable the I/O range before updating PCI_IO_BASE */
6048c2ecf20Sopenharmony_ci	pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff);
6058c2ecf20Sopenharmony_ci	/* Update lower 16 bits of I/O base/limit */
6068c2ecf20Sopenharmony_ci	pci_write_config_word(bridge, PCI_IO_BASE, l);
6078c2ecf20Sopenharmony_ci	/* Update upper 16 bits of I/O base/limit */
6088c2ecf20Sopenharmony_ci	pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, io_upper16);
6098c2ecf20Sopenharmony_ci}
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_cistatic void pci_setup_bridge_mmio(struct pci_dev *bridge)
6128c2ecf20Sopenharmony_ci{
6138c2ecf20Sopenharmony_ci	struct resource *res;
6148c2ecf20Sopenharmony_ci	struct pci_bus_region region;
6158c2ecf20Sopenharmony_ci	u32 l;
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	/* Set up the top and bottom of the PCI Memory segment for this bus */
6188c2ecf20Sopenharmony_ci	res = &bridge->resource[PCI_BRIDGE_MEM_WINDOW];
6198c2ecf20Sopenharmony_ci	pcibios_resource_to_bus(bridge->bus, &region, res);
6208c2ecf20Sopenharmony_ci	if (res->flags & IORESOURCE_MEM) {
6218c2ecf20Sopenharmony_ci		l = (region.start >> 16) & 0xfff0;
6228c2ecf20Sopenharmony_ci		l |= region.end & 0xfff00000;
6238c2ecf20Sopenharmony_ci		pci_info(bridge, "  bridge window %pR\n", res);
6248c2ecf20Sopenharmony_ci	} else {
6258c2ecf20Sopenharmony_ci		l = 0x0000fff0;
6268c2ecf20Sopenharmony_ci	}
6278c2ecf20Sopenharmony_ci	pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
6288c2ecf20Sopenharmony_ci}
6298c2ecf20Sopenharmony_ci
6308c2ecf20Sopenharmony_cistatic void pci_setup_bridge_mmio_pref(struct pci_dev *bridge)
6318c2ecf20Sopenharmony_ci{
6328c2ecf20Sopenharmony_ci	struct resource *res;
6338c2ecf20Sopenharmony_ci	struct pci_bus_region region;
6348c2ecf20Sopenharmony_ci	u32 l, bu, lu;
6358c2ecf20Sopenharmony_ci
6368c2ecf20Sopenharmony_ci	/*
6378c2ecf20Sopenharmony_ci	 * Clear out the upper 32 bits of PREF limit.  If
6388c2ecf20Sopenharmony_ci	 * PCI_PREF_BASE_UPPER32 was non-zero, this temporarily disables
6398c2ecf20Sopenharmony_ci	 * PREF range, which is ok.
6408c2ecf20Sopenharmony_ci	 */
6418c2ecf20Sopenharmony_ci	pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0);
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	/* Set up PREF base/limit */
6448c2ecf20Sopenharmony_ci	bu = lu = 0;
6458c2ecf20Sopenharmony_ci	res = &bridge->resource[PCI_BRIDGE_PREF_MEM_WINDOW];
6468c2ecf20Sopenharmony_ci	pcibios_resource_to_bus(bridge->bus, &region, res);
6478c2ecf20Sopenharmony_ci	if (res->flags & IORESOURCE_PREFETCH) {
6488c2ecf20Sopenharmony_ci		l = (region.start >> 16) & 0xfff0;
6498c2ecf20Sopenharmony_ci		l |= region.end & 0xfff00000;
6508c2ecf20Sopenharmony_ci		if (res->flags & IORESOURCE_MEM_64) {
6518c2ecf20Sopenharmony_ci			bu = upper_32_bits(region.start);
6528c2ecf20Sopenharmony_ci			lu = upper_32_bits(region.end);
6538c2ecf20Sopenharmony_ci		}
6548c2ecf20Sopenharmony_ci		pci_info(bridge, "  bridge window %pR\n", res);
6558c2ecf20Sopenharmony_ci	} else {
6568c2ecf20Sopenharmony_ci		l = 0x0000fff0;
6578c2ecf20Sopenharmony_ci	}
6588c2ecf20Sopenharmony_ci	pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	/* Set the upper 32 bits of PREF base & limit */
6618c2ecf20Sopenharmony_ci	pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu);
6628c2ecf20Sopenharmony_ci	pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu);
6638c2ecf20Sopenharmony_ci}
6648c2ecf20Sopenharmony_ci
6658c2ecf20Sopenharmony_cistatic void __pci_setup_bridge(struct pci_bus *bus, unsigned long type)
6668c2ecf20Sopenharmony_ci{
6678c2ecf20Sopenharmony_ci	struct pci_dev *bridge = bus->self;
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	pci_info(bridge, "PCI bridge to %pR\n",
6708c2ecf20Sopenharmony_ci		 &bus->busn_res);
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	if (type & IORESOURCE_IO)
6738c2ecf20Sopenharmony_ci		pci_setup_bridge_io(bridge);
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	if (type & IORESOURCE_MEM)
6768c2ecf20Sopenharmony_ci		pci_setup_bridge_mmio(bridge);
6778c2ecf20Sopenharmony_ci
6788c2ecf20Sopenharmony_ci	if (type & IORESOURCE_PREFETCH)
6798c2ecf20Sopenharmony_ci		pci_setup_bridge_mmio_pref(bridge);
6808c2ecf20Sopenharmony_ci
6818c2ecf20Sopenharmony_ci	pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl);
6828c2ecf20Sopenharmony_ci}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_civoid __weak pcibios_setup_bridge(struct pci_bus *bus, unsigned long type)
6858c2ecf20Sopenharmony_ci{
6868c2ecf20Sopenharmony_ci}
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_civoid pci_setup_bridge(struct pci_bus *bus)
6898c2ecf20Sopenharmony_ci{
6908c2ecf20Sopenharmony_ci	unsigned long type = IORESOURCE_IO | IORESOURCE_MEM |
6918c2ecf20Sopenharmony_ci				  IORESOURCE_PREFETCH;
6928c2ecf20Sopenharmony_ci
6938c2ecf20Sopenharmony_ci	pcibios_setup_bridge(bus, type);
6948c2ecf20Sopenharmony_ci	__pci_setup_bridge(bus, type);
6958c2ecf20Sopenharmony_ci}
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ciint pci_claim_bridge_resource(struct pci_dev *bridge, int i)
6998c2ecf20Sopenharmony_ci{
7008c2ecf20Sopenharmony_ci	if (i < PCI_BRIDGE_RESOURCES || i > PCI_BRIDGE_RESOURCE_END)
7018c2ecf20Sopenharmony_ci		return 0;
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_ci	if (pci_claim_resource(bridge, i) == 0)
7048c2ecf20Sopenharmony_ci		return 0;	/* Claimed the window */
7058c2ecf20Sopenharmony_ci
7068c2ecf20Sopenharmony_ci	if ((bridge->class >> 8) != PCI_CLASS_BRIDGE_PCI)
7078c2ecf20Sopenharmony_ci		return 0;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci	if (!pci_bus_clip_resource(bridge, i))
7108c2ecf20Sopenharmony_ci		return -EINVAL;	/* Clipping didn't change anything */
7118c2ecf20Sopenharmony_ci
7128c2ecf20Sopenharmony_ci	switch (i) {
7138c2ecf20Sopenharmony_ci	case PCI_BRIDGE_IO_WINDOW:
7148c2ecf20Sopenharmony_ci		pci_setup_bridge_io(bridge);
7158c2ecf20Sopenharmony_ci		break;
7168c2ecf20Sopenharmony_ci	case PCI_BRIDGE_MEM_WINDOW:
7178c2ecf20Sopenharmony_ci		pci_setup_bridge_mmio(bridge);
7188c2ecf20Sopenharmony_ci		break;
7198c2ecf20Sopenharmony_ci	case PCI_BRIDGE_PREF_MEM_WINDOW:
7208c2ecf20Sopenharmony_ci		pci_setup_bridge_mmio_pref(bridge);
7218c2ecf20Sopenharmony_ci		break;
7228c2ecf20Sopenharmony_ci	default:
7238c2ecf20Sopenharmony_ci		return -EINVAL;
7248c2ecf20Sopenharmony_ci	}
7258c2ecf20Sopenharmony_ci
7268c2ecf20Sopenharmony_ci	if (pci_claim_resource(bridge, i) == 0)
7278c2ecf20Sopenharmony_ci		return 0;	/* Claimed a smaller window */
7288c2ecf20Sopenharmony_ci
7298c2ecf20Sopenharmony_ci	return -EINVAL;
7308c2ecf20Sopenharmony_ci}
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci/*
7338c2ecf20Sopenharmony_ci * Check whether the bridge supports optional I/O and prefetchable memory
7348c2ecf20Sopenharmony_ci * ranges.  If not, the respective base/limit registers must be read-only
7358c2ecf20Sopenharmony_ci * and read as 0.
7368c2ecf20Sopenharmony_ci */
7378c2ecf20Sopenharmony_cistatic void pci_bridge_check_ranges(struct pci_bus *bus)
7388c2ecf20Sopenharmony_ci{
7398c2ecf20Sopenharmony_ci	struct pci_dev *bridge = bus->self;
7408c2ecf20Sopenharmony_ci	struct resource *b_res;
7418c2ecf20Sopenharmony_ci
7428c2ecf20Sopenharmony_ci	b_res = &bridge->resource[PCI_BRIDGE_MEM_WINDOW];
7438c2ecf20Sopenharmony_ci	b_res->flags |= IORESOURCE_MEM;
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	if (bridge->io_window) {
7468c2ecf20Sopenharmony_ci		b_res = &bridge->resource[PCI_BRIDGE_IO_WINDOW];
7478c2ecf20Sopenharmony_ci		b_res->flags |= IORESOURCE_IO;
7488c2ecf20Sopenharmony_ci	}
7498c2ecf20Sopenharmony_ci
7508c2ecf20Sopenharmony_ci	if (bridge->pref_window) {
7518c2ecf20Sopenharmony_ci		b_res = &bridge->resource[PCI_BRIDGE_PREF_MEM_WINDOW];
7528c2ecf20Sopenharmony_ci		b_res->flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH;
7538c2ecf20Sopenharmony_ci		if (bridge->pref_64_window) {
7548c2ecf20Sopenharmony_ci			b_res->flags |= IORESOURCE_MEM_64 |
7558c2ecf20Sopenharmony_ci					PCI_PREF_RANGE_TYPE_64;
7568c2ecf20Sopenharmony_ci		}
7578c2ecf20Sopenharmony_ci	}
7588c2ecf20Sopenharmony_ci}
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci/*
7618c2ecf20Sopenharmony_ci * Helper function for sizing routines.  Assigned resources have non-NULL
7628c2ecf20Sopenharmony_ci * parent resource.
7638c2ecf20Sopenharmony_ci *
7648c2ecf20Sopenharmony_ci * Return first unassigned resource of the correct type.  If there is none,
7658c2ecf20Sopenharmony_ci * return first assigned resource of the correct type.  If none of the
7668c2ecf20Sopenharmony_ci * above, return NULL.
7678c2ecf20Sopenharmony_ci *
7688c2ecf20Sopenharmony_ci * Returning an assigned resource of the correct type allows the caller to
7698c2ecf20Sopenharmony_ci * distinguish between already assigned and no resource of the correct type.
7708c2ecf20Sopenharmony_ci */
7718c2ecf20Sopenharmony_cistatic struct resource *find_bus_resource_of_type(struct pci_bus *bus,
7728c2ecf20Sopenharmony_ci						  unsigned long type_mask,
7738c2ecf20Sopenharmony_ci						  unsigned long type)
7748c2ecf20Sopenharmony_ci{
7758c2ecf20Sopenharmony_ci	struct resource *r, *r_assigned = NULL;
7768c2ecf20Sopenharmony_ci	int i;
7778c2ecf20Sopenharmony_ci
7788c2ecf20Sopenharmony_ci	pci_bus_for_each_resource(bus, r, i) {
7798c2ecf20Sopenharmony_ci		if (r == &ioport_resource || r == &iomem_resource)
7808c2ecf20Sopenharmony_ci			continue;
7818c2ecf20Sopenharmony_ci		if (r && (r->flags & type_mask) == type && !r->parent)
7828c2ecf20Sopenharmony_ci			return r;
7838c2ecf20Sopenharmony_ci		if (r && (r->flags & type_mask) == type && !r_assigned)
7848c2ecf20Sopenharmony_ci			r_assigned = r;
7858c2ecf20Sopenharmony_ci	}
7868c2ecf20Sopenharmony_ci	return r_assigned;
7878c2ecf20Sopenharmony_ci}
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_cistatic resource_size_t calculate_iosize(resource_size_t size,
7908c2ecf20Sopenharmony_ci					resource_size_t min_size,
7918c2ecf20Sopenharmony_ci					resource_size_t size1,
7928c2ecf20Sopenharmony_ci					resource_size_t add_size,
7938c2ecf20Sopenharmony_ci					resource_size_t children_add_size,
7948c2ecf20Sopenharmony_ci					resource_size_t old_size,
7958c2ecf20Sopenharmony_ci					resource_size_t align)
7968c2ecf20Sopenharmony_ci{
7978c2ecf20Sopenharmony_ci	if (size < min_size)
7988c2ecf20Sopenharmony_ci		size = min_size;
7998c2ecf20Sopenharmony_ci	if (old_size == 1)
8008c2ecf20Sopenharmony_ci		old_size = 0;
8018c2ecf20Sopenharmony_ci	/*
8028c2ecf20Sopenharmony_ci	 * To be fixed in 2.5: we should have sort of HAVE_ISA flag in the
8038c2ecf20Sopenharmony_ci	 * struct pci_bus.
8048c2ecf20Sopenharmony_ci	 */
8058c2ecf20Sopenharmony_ci#if defined(CONFIG_ISA) || defined(CONFIG_EISA)
8068c2ecf20Sopenharmony_ci	size = (size & 0xff) + ((size & ~0xffUL) << 2);
8078c2ecf20Sopenharmony_ci#endif
8088c2ecf20Sopenharmony_ci	size = size + size1;
8098c2ecf20Sopenharmony_ci	if (size < old_size)
8108c2ecf20Sopenharmony_ci		size = old_size;
8118c2ecf20Sopenharmony_ci
8128c2ecf20Sopenharmony_ci	size = ALIGN(max(size, add_size) + children_add_size, align);
8138c2ecf20Sopenharmony_ci	return size;
8148c2ecf20Sopenharmony_ci}
8158c2ecf20Sopenharmony_ci
8168c2ecf20Sopenharmony_cistatic resource_size_t calculate_memsize(resource_size_t size,
8178c2ecf20Sopenharmony_ci					 resource_size_t min_size,
8188c2ecf20Sopenharmony_ci					 resource_size_t add_size,
8198c2ecf20Sopenharmony_ci					 resource_size_t children_add_size,
8208c2ecf20Sopenharmony_ci					 resource_size_t old_size,
8218c2ecf20Sopenharmony_ci					 resource_size_t align)
8228c2ecf20Sopenharmony_ci{
8238c2ecf20Sopenharmony_ci	if (size < min_size)
8248c2ecf20Sopenharmony_ci		size = min_size;
8258c2ecf20Sopenharmony_ci	if (old_size == 1)
8268c2ecf20Sopenharmony_ci		old_size = 0;
8278c2ecf20Sopenharmony_ci	if (size < old_size)
8288c2ecf20Sopenharmony_ci		size = old_size;
8298c2ecf20Sopenharmony_ci
8308c2ecf20Sopenharmony_ci	size = ALIGN(max(size, add_size) + children_add_size, align);
8318c2ecf20Sopenharmony_ci	return size;
8328c2ecf20Sopenharmony_ci}
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ciresource_size_t __weak pcibios_window_alignment(struct pci_bus *bus,
8358c2ecf20Sopenharmony_ci						unsigned long type)
8368c2ecf20Sopenharmony_ci{
8378c2ecf20Sopenharmony_ci	return 1;
8388c2ecf20Sopenharmony_ci}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci#define PCI_P2P_DEFAULT_MEM_ALIGN	0x100000	/* 1MiB */
8418c2ecf20Sopenharmony_ci#define PCI_P2P_DEFAULT_IO_ALIGN	0x1000		/* 4KiB */
8428c2ecf20Sopenharmony_ci#define PCI_P2P_DEFAULT_IO_ALIGN_1K	0x400		/* 1KiB */
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_cistatic resource_size_t window_alignment(struct pci_bus *bus, unsigned long type)
8458c2ecf20Sopenharmony_ci{
8468c2ecf20Sopenharmony_ci	resource_size_t align = 1, arch_align;
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	if (type & IORESOURCE_MEM)
8498c2ecf20Sopenharmony_ci		align = PCI_P2P_DEFAULT_MEM_ALIGN;
8508c2ecf20Sopenharmony_ci	else if (type & IORESOURCE_IO) {
8518c2ecf20Sopenharmony_ci		/*
8528c2ecf20Sopenharmony_ci		 * Per spec, I/O windows are 4K-aligned, but some bridges have
8538c2ecf20Sopenharmony_ci		 * an extension to support 1K alignment.
8548c2ecf20Sopenharmony_ci		 */
8558c2ecf20Sopenharmony_ci		if (bus->self && bus->self->io_window_1k)
8568c2ecf20Sopenharmony_ci			align = PCI_P2P_DEFAULT_IO_ALIGN_1K;
8578c2ecf20Sopenharmony_ci		else
8588c2ecf20Sopenharmony_ci			align = PCI_P2P_DEFAULT_IO_ALIGN;
8598c2ecf20Sopenharmony_ci	}
8608c2ecf20Sopenharmony_ci
8618c2ecf20Sopenharmony_ci	arch_align = pcibios_window_alignment(bus, type);
8628c2ecf20Sopenharmony_ci	return max(align, arch_align);
8638c2ecf20Sopenharmony_ci}
8648c2ecf20Sopenharmony_ci
8658c2ecf20Sopenharmony_ci/**
8668c2ecf20Sopenharmony_ci * pbus_size_io() - Size the I/O window of a given bus
8678c2ecf20Sopenharmony_ci *
8688c2ecf20Sopenharmony_ci * @bus:		The bus
8698c2ecf20Sopenharmony_ci * @min_size:		The minimum I/O window that must be allocated
8708c2ecf20Sopenharmony_ci * @add_size:		Additional optional I/O window
8718c2ecf20Sopenharmony_ci * @realloc_head:	Track the additional I/O window on this list
8728c2ecf20Sopenharmony_ci *
8738c2ecf20Sopenharmony_ci * Sizing the I/O windows of the PCI-PCI bridge is trivial, since these
8748c2ecf20Sopenharmony_ci * windows have 1K or 4K granularity and the I/O ranges of non-bridge PCI
8758c2ecf20Sopenharmony_ci * devices are limited to 256 bytes.  We must be careful with the ISA
8768c2ecf20Sopenharmony_ci * aliasing though.
8778c2ecf20Sopenharmony_ci */
8788c2ecf20Sopenharmony_cistatic void pbus_size_io(struct pci_bus *bus, resource_size_t min_size,
8798c2ecf20Sopenharmony_ci			 resource_size_t add_size,
8808c2ecf20Sopenharmony_ci			 struct list_head *realloc_head)
8818c2ecf20Sopenharmony_ci{
8828c2ecf20Sopenharmony_ci	struct pci_dev *dev;
8838c2ecf20Sopenharmony_ci	struct resource *b_res = find_bus_resource_of_type(bus, IORESOURCE_IO,
8848c2ecf20Sopenharmony_ci							   IORESOURCE_IO);
8858c2ecf20Sopenharmony_ci	resource_size_t size = 0, size0 = 0, size1 = 0;
8868c2ecf20Sopenharmony_ci	resource_size_t children_add_size = 0;
8878c2ecf20Sopenharmony_ci	resource_size_t min_align, align;
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	if (!b_res)
8908c2ecf20Sopenharmony_ci		return;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	/* If resource is already assigned, nothing more to do */
8938c2ecf20Sopenharmony_ci	if (b_res->parent)
8948c2ecf20Sopenharmony_ci		return;
8958c2ecf20Sopenharmony_ci
8968c2ecf20Sopenharmony_ci	min_align = window_alignment(bus, IORESOURCE_IO);
8978c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &bus->devices, bus_list) {
8988c2ecf20Sopenharmony_ci		int i;
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
9018c2ecf20Sopenharmony_ci			struct resource *r = &dev->resource[i];
9028c2ecf20Sopenharmony_ci			unsigned long r_size;
9038c2ecf20Sopenharmony_ci
9048c2ecf20Sopenharmony_ci			if (r->parent || !(r->flags & IORESOURCE_IO))
9058c2ecf20Sopenharmony_ci				continue;
9068c2ecf20Sopenharmony_ci			r_size = resource_size(r);
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci			if (r_size < 0x400)
9098c2ecf20Sopenharmony_ci				/* Might be re-aligned for ISA */
9108c2ecf20Sopenharmony_ci				size += r_size;
9118c2ecf20Sopenharmony_ci			else
9128c2ecf20Sopenharmony_ci				size1 += r_size;
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci			align = pci_resource_alignment(dev, r);
9158c2ecf20Sopenharmony_ci			if (align > min_align)
9168c2ecf20Sopenharmony_ci				min_align = align;
9178c2ecf20Sopenharmony_ci
9188c2ecf20Sopenharmony_ci			if (realloc_head)
9198c2ecf20Sopenharmony_ci				children_add_size += get_res_add_size(realloc_head, r);
9208c2ecf20Sopenharmony_ci		}
9218c2ecf20Sopenharmony_ci	}
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	size0 = calculate_iosize(size, min_size, size1, 0, 0,
9248c2ecf20Sopenharmony_ci			resource_size(b_res), min_align);
9258c2ecf20Sopenharmony_ci	size1 = (!realloc_head || (realloc_head && !add_size && !children_add_size)) ? size0 :
9268c2ecf20Sopenharmony_ci		calculate_iosize(size, min_size, size1, add_size, children_add_size,
9278c2ecf20Sopenharmony_ci			resource_size(b_res), min_align);
9288c2ecf20Sopenharmony_ci	if (!size0 && !size1) {
9298c2ecf20Sopenharmony_ci		if (bus->self && (b_res->start || b_res->end))
9308c2ecf20Sopenharmony_ci			pci_info(bus->self, "disabling bridge window %pR to %pR (unused)\n",
9318c2ecf20Sopenharmony_ci				 b_res, &bus->busn_res);
9328c2ecf20Sopenharmony_ci		b_res->flags = 0;
9338c2ecf20Sopenharmony_ci		return;
9348c2ecf20Sopenharmony_ci	}
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	b_res->start = min_align;
9378c2ecf20Sopenharmony_ci	b_res->end = b_res->start + size0 - 1;
9388c2ecf20Sopenharmony_ci	b_res->flags |= IORESOURCE_STARTALIGN;
9398c2ecf20Sopenharmony_ci	if (bus->self && size1 > size0 && realloc_head) {
9408c2ecf20Sopenharmony_ci		add_to_list(realloc_head, bus->self, b_res, size1-size0,
9418c2ecf20Sopenharmony_ci			    min_align);
9428c2ecf20Sopenharmony_ci		pci_info(bus->self, "bridge window %pR to %pR add_size %llx\n",
9438c2ecf20Sopenharmony_ci			 b_res, &bus->busn_res,
9448c2ecf20Sopenharmony_ci			 (unsigned long long) size1 - size0);
9458c2ecf20Sopenharmony_ci	}
9468c2ecf20Sopenharmony_ci}
9478c2ecf20Sopenharmony_ci
9488c2ecf20Sopenharmony_cistatic inline resource_size_t calculate_mem_align(resource_size_t *aligns,
9498c2ecf20Sopenharmony_ci						  int max_order)
9508c2ecf20Sopenharmony_ci{
9518c2ecf20Sopenharmony_ci	resource_size_t align = 0;
9528c2ecf20Sopenharmony_ci	resource_size_t min_align = 0;
9538c2ecf20Sopenharmony_ci	int order;
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci	for (order = 0; order <= max_order; order++) {
9568c2ecf20Sopenharmony_ci		resource_size_t align1 = 1;
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci		align1 <<= (order + 20);
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci		if (!align)
9618c2ecf20Sopenharmony_ci			min_align = align1;
9628c2ecf20Sopenharmony_ci		else if (ALIGN(align + min_align, min_align) < align1)
9638c2ecf20Sopenharmony_ci			min_align = align1 >> 1;
9648c2ecf20Sopenharmony_ci		align += aligns[order];
9658c2ecf20Sopenharmony_ci	}
9668c2ecf20Sopenharmony_ci
9678c2ecf20Sopenharmony_ci	return min_align;
9688c2ecf20Sopenharmony_ci}
9698c2ecf20Sopenharmony_ci
9708c2ecf20Sopenharmony_ci/**
9718c2ecf20Sopenharmony_ci * pbus_size_mem() - Size the memory window of a given bus
9728c2ecf20Sopenharmony_ci *
9738c2ecf20Sopenharmony_ci * @bus:		The bus
9748c2ecf20Sopenharmony_ci * @mask:		Mask the resource flag, then compare it with type
9758c2ecf20Sopenharmony_ci * @type:		The type of free resource from bridge
9768c2ecf20Sopenharmony_ci * @type2:		Second match type
9778c2ecf20Sopenharmony_ci * @type3:		Third match type
9788c2ecf20Sopenharmony_ci * @min_size:		The minimum memory window that must be allocated
9798c2ecf20Sopenharmony_ci * @add_size:		Additional optional memory window
9808c2ecf20Sopenharmony_ci * @realloc_head:	Track the additional memory window on this list
9818c2ecf20Sopenharmony_ci *
9828c2ecf20Sopenharmony_ci * Calculate the size of the bus and minimal alignment which guarantees
9838c2ecf20Sopenharmony_ci * that all child resources fit in this size.
9848c2ecf20Sopenharmony_ci *
9858c2ecf20Sopenharmony_ci * Return -ENOSPC if there's no available bus resource of the desired
9868c2ecf20Sopenharmony_ci * type.  Otherwise, set the bus resource start/end to indicate the
9878c2ecf20Sopenharmony_ci * required size, add things to realloc_head (if supplied), and return 0.
9888c2ecf20Sopenharmony_ci */
9898c2ecf20Sopenharmony_cistatic int pbus_size_mem(struct pci_bus *bus, unsigned long mask,
9908c2ecf20Sopenharmony_ci			 unsigned long type, unsigned long type2,
9918c2ecf20Sopenharmony_ci			 unsigned long type3, resource_size_t min_size,
9928c2ecf20Sopenharmony_ci			 resource_size_t add_size,
9938c2ecf20Sopenharmony_ci			 struct list_head *realloc_head)
9948c2ecf20Sopenharmony_ci{
9958c2ecf20Sopenharmony_ci	struct pci_dev *dev;
9968c2ecf20Sopenharmony_ci	resource_size_t min_align, align, size, size0, size1;
9978c2ecf20Sopenharmony_ci	resource_size_t aligns[18]; /* Alignments from 1MB to 128GB */
9988c2ecf20Sopenharmony_ci	int order, max_order;
9998c2ecf20Sopenharmony_ci	struct resource *b_res = find_bus_resource_of_type(bus,
10008c2ecf20Sopenharmony_ci					mask | IORESOURCE_PREFETCH, type);
10018c2ecf20Sopenharmony_ci	resource_size_t children_add_size = 0;
10028c2ecf20Sopenharmony_ci	resource_size_t children_add_align = 0;
10038c2ecf20Sopenharmony_ci	resource_size_t add_align = 0;
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	if (!b_res)
10068c2ecf20Sopenharmony_ci		return -ENOSPC;
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	/* If resource is already assigned, nothing more to do */
10098c2ecf20Sopenharmony_ci	if (b_res->parent)
10108c2ecf20Sopenharmony_ci		return 0;
10118c2ecf20Sopenharmony_ci
10128c2ecf20Sopenharmony_ci	memset(aligns, 0, sizeof(aligns));
10138c2ecf20Sopenharmony_ci	max_order = 0;
10148c2ecf20Sopenharmony_ci	size = 0;
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &bus->devices, bus_list) {
10178c2ecf20Sopenharmony_ci		int i;
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci		for (i = 0; i < PCI_NUM_RESOURCES; i++) {
10208c2ecf20Sopenharmony_ci			struct resource *r = &dev->resource[i];
10218c2ecf20Sopenharmony_ci			resource_size_t r_size;
10228c2ecf20Sopenharmony_ci
10238c2ecf20Sopenharmony_ci			if (r->parent || (r->flags & IORESOURCE_PCI_FIXED) ||
10248c2ecf20Sopenharmony_ci			    ((r->flags & mask) != type &&
10258c2ecf20Sopenharmony_ci			     (r->flags & mask) != type2 &&
10268c2ecf20Sopenharmony_ci			     (r->flags & mask) != type3))
10278c2ecf20Sopenharmony_ci				continue;
10288c2ecf20Sopenharmony_ci			r_size = resource_size(r);
10298c2ecf20Sopenharmony_ci#ifdef CONFIG_PCI_IOV
10308c2ecf20Sopenharmony_ci			/* Put SRIOV requested res to the optional list */
10318c2ecf20Sopenharmony_ci			if (realloc_head && i >= PCI_IOV_RESOURCES &&
10328c2ecf20Sopenharmony_ci					i <= PCI_IOV_RESOURCE_END) {
10338c2ecf20Sopenharmony_ci				add_align = max(pci_resource_alignment(dev, r), add_align);
10348c2ecf20Sopenharmony_ci				r->end = r->start - 1;
10358c2ecf20Sopenharmony_ci				add_to_list(realloc_head, dev, r, r_size, 0 /* Don't care */);
10368c2ecf20Sopenharmony_ci				children_add_size += r_size;
10378c2ecf20Sopenharmony_ci				continue;
10388c2ecf20Sopenharmony_ci			}
10398c2ecf20Sopenharmony_ci#endif
10408c2ecf20Sopenharmony_ci			/*
10418c2ecf20Sopenharmony_ci			 * aligns[0] is for 1MB (since bridge memory
10428c2ecf20Sopenharmony_ci			 * windows are always at least 1MB aligned), so
10438c2ecf20Sopenharmony_ci			 * keep "order" from being negative for smaller
10448c2ecf20Sopenharmony_ci			 * resources.
10458c2ecf20Sopenharmony_ci			 */
10468c2ecf20Sopenharmony_ci			align = pci_resource_alignment(dev, r);
10478c2ecf20Sopenharmony_ci			order = __ffs(align) - 20;
10488c2ecf20Sopenharmony_ci			if (order < 0)
10498c2ecf20Sopenharmony_ci				order = 0;
10508c2ecf20Sopenharmony_ci			if (order >= ARRAY_SIZE(aligns)) {
10518c2ecf20Sopenharmony_ci				pci_warn(dev, "disabling BAR %d: %pR (bad alignment %#llx)\n",
10528c2ecf20Sopenharmony_ci					 i, r, (unsigned long long) align);
10538c2ecf20Sopenharmony_ci				r->flags = 0;
10548c2ecf20Sopenharmony_ci				continue;
10558c2ecf20Sopenharmony_ci			}
10568c2ecf20Sopenharmony_ci			size += max(r_size, align);
10578c2ecf20Sopenharmony_ci			/*
10588c2ecf20Sopenharmony_ci			 * Exclude ranges with size > align from calculation of
10598c2ecf20Sopenharmony_ci			 * the alignment.
10608c2ecf20Sopenharmony_ci			 */
10618c2ecf20Sopenharmony_ci			if (r_size <= align)
10628c2ecf20Sopenharmony_ci				aligns[order] += align;
10638c2ecf20Sopenharmony_ci			if (order > max_order)
10648c2ecf20Sopenharmony_ci				max_order = order;
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci			if (realloc_head) {
10678c2ecf20Sopenharmony_ci				children_add_size += get_res_add_size(realloc_head, r);
10688c2ecf20Sopenharmony_ci				children_add_align = get_res_add_align(realloc_head, r);
10698c2ecf20Sopenharmony_ci				add_align = max(add_align, children_add_align);
10708c2ecf20Sopenharmony_ci			}
10718c2ecf20Sopenharmony_ci		}
10728c2ecf20Sopenharmony_ci	}
10738c2ecf20Sopenharmony_ci
10748c2ecf20Sopenharmony_ci	min_align = calculate_mem_align(aligns, max_order);
10758c2ecf20Sopenharmony_ci	min_align = max(min_align, window_alignment(bus, b_res->flags));
10768c2ecf20Sopenharmony_ci	size0 = calculate_memsize(size, min_size, 0, 0, resource_size(b_res), min_align);
10778c2ecf20Sopenharmony_ci	add_align = max(min_align, add_align);
10788c2ecf20Sopenharmony_ci	size1 = (!realloc_head || (realloc_head && !add_size && !children_add_size)) ? size0 :
10798c2ecf20Sopenharmony_ci		calculate_memsize(size, min_size, add_size, children_add_size,
10808c2ecf20Sopenharmony_ci				resource_size(b_res), add_align);
10818c2ecf20Sopenharmony_ci	if (!size0 && !size1) {
10828c2ecf20Sopenharmony_ci		if (bus->self && (b_res->start || b_res->end))
10838c2ecf20Sopenharmony_ci			pci_info(bus->self, "disabling bridge window %pR to %pR (unused)\n",
10848c2ecf20Sopenharmony_ci				 b_res, &bus->busn_res);
10858c2ecf20Sopenharmony_ci		b_res->flags = 0;
10868c2ecf20Sopenharmony_ci		return 0;
10878c2ecf20Sopenharmony_ci	}
10888c2ecf20Sopenharmony_ci	b_res->start = min_align;
10898c2ecf20Sopenharmony_ci	b_res->end = size0 + min_align - 1;
10908c2ecf20Sopenharmony_ci	b_res->flags |= IORESOURCE_STARTALIGN;
10918c2ecf20Sopenharmony_ci	if (bus->self && size1 > size0 && realloc_head) {
10928c2ecf20Sopenharmony_ci		add_to_list(realloc_head, bus->self, b_res, size1-size0, add_align);
10938c2ecf20Sopenharmony_ci		pci_info(bus->self, "bridge window %pR to %pR add_size %llx add_align %llx\n",
10948c2ecf20Sopenharmony_ci			   b_res, &bus->busn_res,
10958c2ecf20Sopenharmony_ci			   (unsigned long long) (size1 - size0),
10968c2ecf20Sopenharmony_ci			   (unsigned long long) add_align);
10978c2ecf20Sopenharmony_ci	}
10988c2ecf20Sopenharmony_ci	return 0;
10998c2ecf20Sopenharmony_ci}
11008c2ecf20Sopenharmony_ci
11018c2ecf20Sopenharmony_ciunsigned long pci_cardbus_resource_alignment(struct resource *res)
11028c2ecf20Sopenharmony_ci{
11038c2ecf20Sopenharmony_ci	if (res->flags & IORESOURCE_IO)
11048c2ecf20Sopenharmony_ci		return pci_cardbus_io_size;
11058c2ecf20Sopenharmony_ci	if (res->flags & IORESOURCE_MEM)
11068c2ecf20Sopenharmony_ci		return pci_cardbus_mem_size;
11078c2ecf20Sopenharmony_ci	return 0;
11088c2ecf20Sopenharmony_ci}
11098c2ecf20Sopenharmony_ci
11108c2ecf20Sopenharmony_cistatic void pci_bus_size_cardbus(struct pci_bus *bus,
11118c2ecf20Sopenharmony_ci				 struct list_head *realloc_head)
11128c2ecf20Sopenharmony_ci{
11138c2ecf20Sopenharmony_ci	struct pci_dev *bridge = bus->self;
11148c2ecf20Sopenharmony_ci	struct resource *b_res;
11158c2ecf20Sopenharmony_ci	resource_size_t b_res_3_size = pci_cardbus_mem_size * 2;
11168c2ecf20Sopenharmony_ci	u16 ctrl;
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	b_res = &bridge->resource[PCI_CB_BRIDGE_IO_0_WINDOW];
11198c2ecf20Sopenharmony_ci	if (b_res->parent)
11208c2ecf20Sopenharmony_ci		goto handle_b_res_1;
11218c2ecf20Sopenharmony_ci	/*
11228c2ecf20Sopenharmony_ci	 * Reserve some resources for CardBus.  We reserve a fixed amount
11238c2ecf20Sopenharmony_ci	 * of bus space for CardBus bridges.
11248c2ecf20Sopenharmony_ci	 */
11258c2ecf20Sopenharmony_ci	b_res->start = pci_cardbus_io_size;
11268c2ecf20Sopenharmony_ci	b_res->end = b_res->start + pci_cardbus_io_size - 1;
11278c2ecf20Sopenharmony_ci	b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
11288c2ecf20Sopenharmony_ci	if (realloc_head) {
11298c2ecf20Sopenharmony_ci		b_res->end -= pci_cardbus_io_size;
11308c2ecf20Sopenharmony_ci		add_to_list(realloc_head, bridge, b_res, pci_cardbus_io_size,
11318c2ecf20Sopenharmony_ci			    pci_cardbus_io_size);
11328c2ecf20Sopenharmony_ci	}
11338c2ecf20Sopenharmony_ci
11348c2ecf20Sopenharmony_cihandle_b_res_1:
11358c2ecf20Sopenharmony_ci	b_res = &bridge->resource[PCI_CB_BRIDGE_IO_1_WINDOW];
11368c2ecf20Sopenharmony_ci	if (b_res->parent)
11378c2ecf20Sopenharmony_ci		goto handle_b_res_2;
11388c2ecf20Sopenharmony_ci	b_res->start = pci_cardbus_io_size;
11398c2ecf20Sopenharmony_ci	b_res->end = b_res->start + pci_cardbus_io_size - 1;
11408c2ecf20Sopenharmony_ci	b_res->flags |= IORESOURCE_IO | IORESOURCE_STARTALIGN;
11418c2ecf20Sopenharmony_ci	if (realloc_head) {
11428c2ecf20Sopenharmony_ci		b_res->end -= pci_cardbus_io_size;
11438c2ecf20Sopenharmony_ci		add_to_list(realloc_head, bridge, b_res, pci_cardbus_io_size,
11448c2ecf20Sopenharmony_ci			    pci_cardbus_io_size);
11458c2ecf20Sopenharmony_ci	}
11468c2ecf20Sopenharmony_ci
11478c2ecf20Sopenharmony_cihandle_b_res_2:
11488c2ecf20Sopenharmony_ci	/* MEM1 must not be pref MMIO */
11498c2ecf20Sopenharmony_ci	pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
11508c2ecf20Sopenharmony_ci	if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM1) {
11518c2ecf20Sopenharmony_ci		ctrl &= ~PCI_CB_BRIDGE_CTL_PREFETCH_MEM1;
11528c2ecf20Sopenharmony_ci		pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl);
11538c2ecf20Sopenharmony_ci		pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
11548c2ecf20Sopenharmony_ci	}
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci	/* Check whether prefetchable memory is supported by this bridge. */
11578c2ecf20Sopenharmony_ci	pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
11588c2ecf20Sopenharmony_ci	if (!(ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0)) {
11598c2ecf20Sopenharmony_ci		ctrl |= PCI_CB_BRIDGE_CTL_PREFETCH_MEM0;
11608c2ecf20Sopenharmony_ci		pci_write_config_word(bridge, PCI_CB_BRIDGE_CONTROL, ctrl);
11618c2ecf20Sopenharmony_ci		pci_read_config_word(bridge, PCI_CB_BRIDGE_CONTROL, &ctrl);
11628c2ecf20Sopenharmony_ci	}
11638c2ecf20Sopenharmony_ci
11648c2ecf20Sopenharmony_ci	b_res = &bridge->resource[PCI_CB_BRIDGE_MEM_0_WINDOW];
11658c2ecf20Sopenharmony_ci	if (b_res->parent)
11668c2ecf20Sopenharmony_ci		goto handle_b_res_3;
11678c2ecf20Sopenharmony_ci	/*
11688c2ecf20Sopenharmony_ci	 * If we have prefetchable memory support, allocate two regions.
11698c2ecf20Sopenharmony_ci	 * Otherwise, allocate one region of twice the size.
11708c2ecf20Sopenharmony_ci	 */
11718c2ecf20Sopenharmony_ci	if (ctrl & PCI_CB_BRIDGE_CTL_PREFETCH_MEM0) {
11728c2ecf20Sopenharmony_ci		b_res->start = pci_cardbus_mem_size;
11738c2ecf20Sopenharmony_ci		b_res->end = b_res->start + pci_cardbus_mem_size - 1;
11748c2ecf20Sopenharmony_ci		b_res->flags |= IORESOURCE_MEM | IORESOURCE_PREFETCH |
11758c2ecf20Sopenharmony_ci				    IORESOURCE_STARTALIGN;
11768c2ecf20Sopenharmony_ci		if (realloc_head) {
11778c2ecf20Sopenharmony_ci			b_res->end -= pci_cardbus_mem_size;
11788c2ecf20Sopenharmony_ci			add_to_list(realloc_head, bridge, b_res,
11798c2ecf20Sopenharmony_ci				    pci_cardbus_mem_size, pci_cardbus_mem_size);
11808c2ecf20Sopenharmony_ci		}
11818c2ecf20Sopenharmony_ci
11828c2ecf20Sopenharmony_ci		/* Reduce that to half */
11838c2ecf20Sopenharmony_ci		b_res_3_size = pci_cardbus_mem_size;
11848c2ecf20Sopenharmony_ci	}
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_cihandle_b_res_3:
11878c2ecf20Sopenharmony_ci	b_res = &bridge->resource[PCI_CB_BRIDGE_MEM_1_WINDOW];
11888c2ecf20Sopenharmony_ci	if (b_res->parent)
11898c2ecf20Sopenharmony_ci		goto handle_done;
11908c2ecf20Sopenharmony_ci	b_res->start = pci_cardbus_mem_size;
11918c2ecf20Sopenharmony_ci	b_res->end = b_res->start + b_res_3_size - 1;
11928c2ecf20Sopenharmony_ci	b_res->flags |= IORESOURCE_MEM | IORESOURCE_STARTALIGN;
11938c2ecf20Sopenharmony_ci	if (realloc_head) {
11948c2ecf20Sopenharmony_ci		b_res->end -= b_res_3_size;
11958c2ecf20Sopenharmony_ci		add_to_list(realloc_head, bridge, b_res, b_res_3_size,
11968c2ecf20Sopenharmony_ci			    pci_cardbus_mem_size);
11978c2ecf20Sopenharmony_ci	}
11988c2ecf20Sopenharmony_ci
11998c2ecf20Sopenharmony_cihandle_done:
12008c2ecf20Sopenharmony_ci	;
12018c2ecf20Sopenharmony_ci}
12028c2ecf20Sopenharmony_ci
12038c2ecf20Sopenharmony_civoid __pci_bus_size_bridges(struct pci_bus *bus, struct list_head *realloc_head)
12048c2ecf20Sopenharmony_ci{
12058c2ecf20Sopenharmony_ci	struct pci_dev *dev;
12068c2ecf20Sopenharmony_ci	unsigned long mask, prefmask, type2 = 0, type3 = 0;
12078c2ecf20Sopenharmony_ci	resource_size_t additional_io_size = 0, additional_mmio_size = 0,
12088c2ecf20Sopenharmony_ci			additional_mmio_pref_size = 0;
12098c2ecf20Sopenharmony_ci	struct resource *pref;
12108c2ecf20Sopenharmony_ci	struct pci_host_bridge *host;
12118c2ecf20Sopenharmony_ci	int hdr_type, i, ret;
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &bus->devices, bus_list) {
12148c2ecf20Sopenharmony_ci		struct pci_bus *b = dev->subordinate;
12158c2ecf20Sopenharmony_ci		if (!b)
12168c2ecf20Sopenharmony_ci			continue;
12178c2ecf20Sopenharmony_ci
12188c2ecf20Sopenharmony_ci		switch (dev->hdr_type) {
12198c2ecf20Sopenharmony_ci		case PCI_HEADER_TYPE_CARDBUS:
12208c2ecf20Sopenharmony_ci			pci_bus_size_cardbus(b, realloc_head);
12218c2ecf20Sopenharmony_ci			break;
12228c2ecf20Sopenharmony_ci
12238c2ecf20Sopenharmony_ci		case PCI_HEADER_TYPE_BRIDGE:
12248c2ecf20Sopenharmony_ci		default:
12258c2ecf20Sopenharmony_ci			__pci_bus_size_bridges(b, realloc_head);
12268c2ecf20Sopenharmony_ci			break;
12278c2ecf20Sopenharmony_ci		}
12288c2ecf20Sopenharmony_ci	}
12298c2ecf20Sopenharmony_ci
12308c2ecf20Sopenharmony_ci	/* The root bus? */
12318c2ecf20Sopenharmony_ci	if (pci_is_root_bus(bus)) {
12328c2ecf20Sopenharmony_ci		host = to_pci_host_bridge(bus->bridge);
12338c2ecf20Sopenharmony_ci		if (!host->size_windows)
12348c2ecf20Sopenharmony_ci			return;
12358c2ecf20Sopenharmony_ci		pci_bus_for_each_resource(bus, pref, i)
12368c2ecf20Sopenharmony_ci			if (pref && (pref->flags & IORESOURCE_PREFETCH))
12378c2ecf20Sopenharmony_ci				break;
12388c2ecf20Sopenharmony_ci		hdr_type = -1;	/* Intentionally invalid - not a PCI device. */
12398c2ecf20Sopenharmony_ci	} else {
12408c2ecf20Sopenharmony_ci		pref = &bus->self->resource[PCI_BRIDGE_PREF_MEM_WINDOW];
12418c2ecf20Sopenharmony_ci		hdr_type = bus->self->hdr_type;
12428c2ecf20Sopenharmony_ci	}
12438c2ecf20Sopenharmony_ci
12448c2ecf20Sopenharmony_ci	switch (hdr_type) {
12458c2ecf20Sopenharmony_ci	case PCI_HEADER_TYPE_CARDBUS:
12468c2ecf20Sopenharmony_ci		/* Don't size CardBuses yet */
12478c2ecf20Sopenharmony_ci		break;
12488c2ecf20Sopenharmony_ci
12498c2ecf20Sopenharmony_ci	case PCI_HEADER_TYPE_BRIDGE:
12508c2ecf20Sopenharmony_ci		pci_bridge_check_ranges(bus);
12518c2ecf20Sopenharmony_ci		if (bus->self->is_hotplug_bridge) {
12528c2ecf20Sopenharmony_ci			additional_io_size  = pci_hotplug_io_size;
12538c2ecf20Sopenharmony_ci			additional_mmio_size = pci_hotplug_mmio_size;
12548c2ecf20Sopenharmony_ci			additional_mmio_pref_size = pci_hotplug_mmio_pref_size;
12558c2ecf20Sopenharmony_ci		}
12568c2ecf20Sopenharmony_ci		fallthrough;
12578c2ecf20Sopenharmony_ci	default:
12588c2ecf20Sopenharmony_ci		pbus_size_io(bus, realloc_head ? 0 : additional_io_size,
12598c2ecf20Sopenharmony_ci			     additional_io_size, realloc_head);
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_ci		/*
12628c2ecf20Sopenharmony_ci		 * If there's a 64-bit prefetchable MMIO window, compute
12638c2ecf20Sopenharmony_ci		 * the size required to put all 64-bit prefetchable
12648c2ecf20Sopenharmony_ci		 * resources in it.
12658c2ecf20Sopenharmony_ci		 */
12668c2ecf20Sopenharmony_ci		mask = IORESOURCE_MEM;
12678c2ecf20Sopenharmony_ci		prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH;
12688c2ecf20Sopenharmony_ci		if (pref && (pref->flags & IORESOURCE_MEM_64)) {
12698c2ecf20Sopenharmony_ci			prefmask |= IORESOURCE_MEM_64;
12708c2ecf20Sopenharmony_ci			ret = pbus_size_mem(bus, prefmask, prefmask,
12718c2ecf20Sopenharmony_ci				prefmask, prefmask,
12728c2ecf20Sopenharmony_ci				realloc_head ? 0 : additional_mmio_pref_size,
12738c2ecf20Sopenharmony_ci				additional_mmio_pref_size, realloc_head);
12748c2ecf20Sopenharmony_ci
12758c2ecf20Sopenharmony_ci			/*
12768c2ecf20Sopenharmony_ci			 * If successful, all non-prefetchable resources
12778c2ecf20Sopenharmony_ci			 * and any 32-bit prefetchable resources will go in
12788c2ecf20Sopenharmony_ci			 * the non-prefetchable window.
12798c2ecf20Sopenharmony_ci			 */
12808c2ecf20Sopenharmony_ci			if (ret == 0) {
12818c2ecf20Sopenharmony_ci				mask = prefmask;
12828c2ecf20Sopenharmony_ci				type2 = prefmask & ~IORESOURCE_MEM_64;
12838c2ecf20Sopenharmony_ci				type3 = prefmask & ~IORESOURCE_PREFETCH;
12848c2ecf20Sopenharmony_ci			}
12858c2ecf20Sopenharmony_ci		}
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci		/*
12888c2ecf20Sopenharmony_ci		 * If there is no 64-bit prefetchable window, compute the
12898c2ecf20Sopenharmony_ci		 * size required to put all prefetchable resources in the
12908c2ecf20Sopenharmony_ci		 * 32-bit prefetchable window (if there is one).
12918c2ecf20Sopenharmony_ci		 */
12928c2ecf20Sopenharmony_ci		if (!type2) {
12938c2ecf20Sopenharmony_ci			prefmask &= ~IORESOURCE_MEM_64;
12948c2ecf20Sopenharmony_ci			ret = pbus_size_mem(bus, prefmask, prefmask,
12958c2ecf20Sopenharmony_ci				prefmask, prefmask,
12968c2ecf20Sopenharmony_ci				realloc_head ? 0 : additional_mmio_pref_size,
12978c2ecf20Sopenharmony_ci				additional_mmio_pref_size, realloc_head);
12988c2ecf20Sopenharmony_ci
12998c2ecf20Sopenharmony_ci			/*
13008c2ecf20Sopenharmony_ci			 * If successful, only non-prefetchable resources
13018c2ecf20Sopenharmony_ci			 * will go in the non-prefetchable window.
13028c2ecf20Sopenharmony_ci			 */
13038c2ecf20Sopenharmony_ci			if (ret == 0)
13048c2ecf20Sopenharmony_ci				mask = prefmask;
13058c2ecf20Sopenharmony_ci			else
13068c2ecf20Sopenharmony_ci				additional_mmio_size += additional_mmio_pref_size;
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci			type2 = type3 = IORESOURCE_MEM;
13098c2ecf20Sopenharmony_ci		}
13108c2ecf20Sopenharmony_ci
13118c2ecf20Sopenharmony_ci		/*
13128c2ecf20Sopenharmony_ci		 * Compute the size required to put everything else in the
13138c2ecf20Sopenharmony_ci		 * non-prefetchable window. This includes:
13148c2ecf20Sopenharmony_ci		 *
13158c2ecf20Sopenharmony_ci		 *   - all non-prefetchable resources
13168c2ecf20Sopenharmony_ci		 *   - 32-bit prefetchable resources if there's a 64-bit
13178c2ecf20Sopenharmony_ci		 *     prefetchable window or no prefetchable window at all
13188c2ecf20Sopenharmony_ci		 *   - 64-bit prefetchable resources if there's no prefetchable
13198c2ecf20Sopenharmony_ci		 *     window at all
13208c2ecf20Sopenharmony_ci		 *
13218c2ecf20Sopenharmony_ci		 * Note that the strategy in __pci_assign_resource() must match
13228c2ecf20Sopenharmony_ci		 * that used here. Specifically, we cannot put a 32-bit
13238c2ecf20Sopenharmony_ci		 * prefetchable resource in a 64-bit prefetchable window.
13248c2ecf20Sopenharmony_ci		 */
13258c2ecf20Sopenharmony_ci		pbus_size_mem(bus, mask, IORESOURCE_MEM, type2, type3,
13268c2ecf20Sopenharmony_ci			      realloc_head ? 0 : additional_mmio_size,
13278c2ecf20Sopenharmony_ci			      additional_mmio_size, realloc_head);
13288c2ecf20Sopenharmony_ci		break;
13298c2ecf20Sopenharmony_ci	}
13308c2ecf20Sopenharmony_ci}
13318c2ecf20Sopenharmony_ci
13328c2ecf20Sopenharmony_civoid pci_bus_size_bridges(struct pci_bus *bus)
13338c2ecf20Sopenharmony_ci{
13348c2ecf20Sopenharmony_ci	__pci_bus_size_bridges(bus, NULL);
13358c2ecf20Sopenharmony_ci}
13368c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_bus_size_bridges);
13378c2ecf20Sopenharmony_ci
13388c2ecf20Sopenharmony_cistatic void assign_fixed_resource_on_bus(struct pci_bus *b, struct resource *r)
13398c2ecf20Sopenharmony_ci{
13408c2ecf20Sopenharmony_ci	int i;
13418c2ecf20Sopenharmony_ci	struct resource *parent_r;
13428c2ecf20Sopenharmony_ci	unsigned long mask = IORESOURCE_IO | IORESOURCE_MEM |
13438c2ecf20Sopenharmony_ci			     IORESOURCE_PREFETCH;
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_ci	pci_bus_for_each_resource(b, parent_r, i) {
13468c2ecf20Sopenharmony_ci		if (!parent_r)
13478c2ecf20Sopenharmony_ci			continue;
13488c2ecf20Sopenharmony_ci
13498c2ecf20Sopenharmony_ci		if ((r->flags & mask) == (parent_r->flags & mask) &&
13508c2ecf20Sopenharmony_ci		    resource_contains(parent_r, r))
13518c2ecf20Sopenharmony_ci			request_resource(parent_r, r);
13528c2ecf20Sopenharmony_ci	}
13538c2ecf20Sopenharmony_ci}
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci/*
13568c2ecf20Sopenharmony_ci * Try to assign any resources marked as IORESOURCE_PCI_FIXED, as they are
13578c2ecf20Sopenharmony_ci * skipped by pbus_assign_resources_sorted().
13588c2ecf20Sopenharmony_ci */
13598c2ecf20Sopenharmony_cistatic void pdev_assign_fixed_resources(struct pci_dev *dev)
13608c2ecf20Sopenharmony_ci{
13618c2ecf20Sopenharmony_ci	int i;
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci	for (i = 0; i <  PCI_NUM_RESOURCES; i++) {
13648c2ecf20Sopenharmony_ci		struct pci_bus *b;
13658c2ecf20Sopenharmony_ci		struct resource *r = &dev->resource[i];
13668c2ecf20Sopenharmony_ci
13678c2ecf20Sopenharmony_ci		if (r->parent || !(r->flags & IORESOURCE_PCI_FIXED) ||
13688c2ecf20Sopenharmony_ci		    !(r->flags & (IORESOURCE_IO | IORESOURCE_MEM)))
13698c2ecf20Sopenharmony_ci			continue;
13708c2ecf20Sopenharmony_ci
13718c2ecf20Sopenharmony_ci		b = dev->bus;
13728c2ecf20Sopenharmony_ci		while (b && !r->parent) {
13738c2ecf20Sopenharmony_ci			assign_fixed_resource_on_bus(b, r);
13748c2ecf20Sopenharmony_ci			b = b->parent;
13758c2ecf20Sopenharmony_ci		}
13768c2ecf20Sopenharmony_ci	}
13778c2ecf20Sopenharmony_ci}
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_civoid __pci_bus_assign_resources(const struct pci_bus *bus,
13808c2ecf20Sopenharmony_ci				struct list_head *realloc_head,
13818c2ecf20Sopenharmony_ci				struct list_head *fail_head)
13828c2ecf20Sopenharmony_ci{
13838c2ecf20Sopenharmony_ci	struct pci_bus *b;
13848c2ecf20Sopenharmony_ci	struct pci_dev *dev;
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_ci	pbus_assign_resources_sorted(bus, realloc_head, fail_head);
13878c2ecf20Sopenharmony_ci
13888c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &bus->devices, bus_list) {
13898c2ecf20Sopenharmony_ci		pdev_assign_fixed_resources(dev);
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_ci		b = dev->subordinate;
13928c2ecf20Sopenharmony_ci		if (!b)
13938c2ecf20Sopenharmony_ci			continue;
13948c2ecf20Sopenharmony_ci
13958c2ecf20Sopenharmony_ci		__pci_bus_assign_resources(b, realloc_head, fail_head);
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci		switch (dev->hdr_type) {
13988c2ecf20Sopenharmony_ci		case PCI_HEADER_TYPE_BRIDGE:
13998c2ecf20Sopenharmony_ci			if (!pci_is_enabled(dev))
14008c2ecf20Sopenharmony_ci				pci_setup_bridge(b);
14018c2ecf20Sopenharmony_ci			break;
14028c2ecf20Sopenharmony_ci
14038c2ecf20Sopenharmony_ci		case PCI_HEADER_TYPE_CARDBUS:
14048c2ecf20Sopenharmony_ci			pci_setup_cardbus(b);
14058c2ecf20Sopenharmony_ci			break;
14068c2ecf20Sopenharmony_ci
14078c2ecf20Sopenharmony_ci		default:
14088c2ecf20Sopenharmony_ci			pci_info(dev, "not setting up bridge for bus %04x:%02x\n",
14098c2ecf20Sopenharmony_ci				 pci_domain_nr(b), b->number);
14108c2ecf20Sopenharmony_ci			break;
14118c2ecf20Sopenharmony_ci		}
14128c2ecf20Sopenharmony_ci	}
14138c2ecf20Sopenharmony_ci}
14148c2ecf20Sopenharmony_ci
14158c2ecf20Sopenharmony_civoid pci_bus_assign_resources(const struct pci_bus *bus)
14168c2ecf20Sopenharmony_ci{
14178c2ecf20Sopenharmony_ci	__pci_bus_assign_resources(bus, NULL, NULL);
14188c2ecf20Sopenharmony_ci}
14198c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_bus_assign_resources);
14208c2ecf20Sopenharmony_ci
14218c2ecf20Sopenharmony_cistatic void pci_claim_device_resources(struct pci_dev *dev)
14228c2ecf20Sopenharmony_ci{
14238c2ecf20Sopenharmony_ci	int i;
14248c2ecf20Sopenharmony_ci
14258c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) {
14268c2ecf20Sopenharmony_ci		struct resource *r = &dev->resource[i];
14278c2ecf20Sopenharmony_ci
14288c2ecf20Sopenharmony_ci		if (!r->flags || r->parent)
14298c2ecf20Sopenharmony_ci			continue;
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci		pci_claim_resource(dev, i);
14328c2ecf20Sopenharmony_ci	}
14338c2ecf20Sopenharmony_ci}
14348c2ecf20Sopenharmony_ci
14358c2ecf20Sopenharmony_cistatic void pci_claim_bridge_resources(struct pci_dev *dev)
14368c2ecf20Sopenharmony_ci{
14378c2ecf20Sopenharmony_ci	int i;
14388c2ecf20Sopenharmony_ci
14398c2ecf20Sopenharmony_ci	for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
14408c2ecf20Sopenharmony_ci		struct resource *r = &dev->resource[i];
14418c2ecf20Sopenharmony_ci
14428c2ecf20Sopenharmony_ci		if (!r->flags || r->parent)
14438c2ecf20Sopenharmony_ci			continue;
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_ci		pci_claim_bridge_resource(dev, i);
14468c2ecf20Sopenharmony_ci	}
14478c2ecf20Sopenharmony_ci}
14488c2ecf20Sopenharmony_ci
14498c2ecf20Sopenharmony_cistatic void pci_bus_allocate_dev_resources(struct pci_bus *b)
14508c2ecf20Sopenharmony_ci{
14518c2ecf20Sopenharmony_ci	struct pci_dev *dev;
14528c2ecf20Sopenharmony_ci	struct pci_bus *child;
14538c2ecf20Sopenharmony_ci
14548c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &b->devices, bus_list) {
14558c2ecf20Sopenharmony_ci		pci_claim_device_resources(dev);
14568c2ecf20Sopenharmony_ci
14578c2ecf20Sopenharmony_ci		child = dev->subordinate;
14588c2ecf20Sopenharmony_ci		if (child)
14598c2ecf20Sopenharmony_ci			pci_bus_allocate_dev_resources(child);
14608c2ecf20Sopenharmony_ci	}
14618c2ecf20Sopenharmony_ci}
14628c2ecf20Sopenharmony_ci
14638c2ecf20Sopenharmony_cistatic void pci_bus_allocate_resources(struct pci_bus *b)
14648c2ecf20Sopenharmony_ci{
14658c2ecf20Sopenharmony_ci	struct pci_bus *child;
14668c2ecf20Sopenharmony_ci
14678c2ecf20Sopenharmony_ci	/*
14688c2ecf20Sopenharmony_ci	 * Carry out a depth-first search on the PCI bus tree to allocate
14698c2ecf20Sopenharmony_ci	 * bridge apertures.  Read the programmed bridge bases and
14708c2ecf20Sopenharmony_ci	 * recursively claim the respective bridge resources.
14718c2ecf20Sopenharmony_ci	 */
14728c2ecf20Sopenharmony_ci	if (b->self) {
14738c2ecf20Sopenharmony_ci		pci_read_bridge_bases(b);
14748c2ecf20Sopenharmony_ci		pci_claim_bridge_resources(b->self);
14758c2ecf20Sopenharmony_ci	}
14768c2ecf20Sopenharmony_ci
14778c2ecf20Sopenharmony_ci	list_for_each_entry(child, &b->children, node)
14788c2ecf20Sopenharmony_ci		pci_bus_allocate_resources(child);
14798c2ecf20Sopenharmony_ci}
14808c2ecf20Sopenharmony_ci
14818c2ecf20Sopenharmony_civoid pci_bus_claim_resources(struct pci_bus *b)
14828c2ecf20Sopenharmony_ci{
14838c2ecf20Sopenharmony_ci	pci_bus_allocate_resources(b);
14848c2ecf20Sopenharmony_ci	pci_bus_allocate_dev_resources(b);
14858c2ecf20Sopenharmony_ci}
14868c2ecf20Sopenharmony_ciEXPORT_SYMBOL(pci_bus_claim_resources);
14878c2ecf20Sopenharmony_ci
14888c2ecf20Sopenharmony_cistatic void __pci_bridge_assign_resources(const struct pci_dev *bridge,
14898c2ecf20Sopenharmony_ci					  struct list_head *add_head,
14908c2ecf20Sopenharmony_ci					  struct list_head *fail_head)
14918c2ecf20Sopenharmony_ci{
14928c2ecf20Sopenharmony_ci	struct pci_bus *b;
14938c2ecf20Sopenharmony_ci
14948c2ecf20Sopenharmony_ci	pdev_assign_resources_sorted((struct pci_dev *)bridge,
14958c2ecf20Sopenharmony_ci					 add_head, fail_head);
14968c2ecf20Sopenharmony_ci
14978c2ecf20Sopenharmony_ci	b = bridge->subordinate;
14988c2ecf20Sopenharmony_ci	if (!b)
14998c2ecf20Sopenharmony_ci		return;
15008c2ecf20Sopenharmony_ci
15018c2ecf20Sopenharmony_ci	__pci_bus_assign_resources(b, add_head, fail_head);
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci	switch (bridge->class >> 8) {
15048c2ecf20Sopenharmony_ci	case PCI_CLASS_BRIDGE_PCI:
15058c2ecf20Sopenharmony_ci		pci_setup_bridge(b);
15068c2ecf20Sopenharmony_ci		break;
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	case PCI_CLASS_BRIDGE_CARDBUS:
15098c2ecf20Sopenharmony_ci		pci_setup_cardbus(b);
15108c2ecf20Sopenharmony_ci		break;
15118c2ecf20Sopenharmony_ci
15128c2ecf20Sopenharmony_ci	default:
15138c2ecf20Sopenharmony_ci		pci_info(bridge, "not setting up bridge for bus %04x:%02x\n",
15148c2ecf20Sopenharmony_ci			 pci_domain_nr(b), b->number);
15158c2ecf20Sopenharmony_ci		break;
15168c2ecf20Sopenharmony_ci	}
15178c2ecf20Sopenharmony_ci}
15188c2ecf20Sopenharmony_ci
15198c2ecf20Sopenharmony_ci#define PCI_RES_TYPE_MASK \
15208c2ecf20Sopenharmony_ci	(IORESOURCE_IO | IORESOURCE_MEM | IORESOURCE_PREFETCH |\
15218c2ecf20Sopenharmony_ci	 IORESOURCE_MEM_64)
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_cistatic void pci_bridge_release_resources(struct pci_bus *bus,
15248c2ecf20Sopenharmony_ci					 unsigned long type)
15258c2ecf20Sopenharmony_ci{
15268c2ecf20Sopenharmony_ci	struct pci_dev *dev = bus->self;
15278c2ecf20Sopenharmony_ci	struct resource *r;
15288c2ecf20Sopenharmony_ci	unsigned old_flags = 0;
15298c2ecf20Sopenharmony_ci	struct resource *b_res;
15308c2ecf20Sopenharmony_ci	int idx = 1;
15318c2ecf20Sopenharmony_ci
15328c2ecf20Sopenharmony_ci	b_res = &dev->resource[PCI_BRIDGE_RESOURCES];
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	/*
15358c2ecf20Sopenharmony_ci	 * 1. If IO port assignment fails, release bridge IO port.
15368c2ecf20Sopenharmony_ci	 * 2. If non pref MMIO assignment fails, release bridge nonpref MMIO.
15378c2ecf20Sopenharmony_ci	 * 3. If 64bit pref MMIO assignment fails, and bridge pref is 64bit,
15388c2ecf20Sopenharmony_ci	 *    release bridge pref MMIO.
15398c2ecf20Sopenharmony_ci	 * 4. If pref MMIO assignment fails, and bridge pref is 32bit,
15408c2ecf20Sopenharmony_ci	 *    release bridge pref MMIO.
15418c2ecf20Sopenharmony_ci	 * 5. If pref MMIO assignment fails, and bridge pref is not
15428c2ecf20Sopenharmony_ci	 *    assigned, release bridge nonpref MMIO.
15438c2ecf20Sopenharmony_ci	 */
15448c2ecf20Sopenharmony_ci	if (type & IORESOURCE_IO)
15458c2ecf20Sopenharmony_ci		idx = 0;
15468c2ecf20Sopenharmony_ci	else if (!(type & IORESOURCE_PREFETCH))
15478c2ecf20Sopenharmony_ci		idx = 1;
15488c2ecf20Sopenharmony_ci	else if ((type & IORESOURCE_MEM_64) &&
15498c2ecf20Sopenharmony_ci		 (b_res[2].flags & IORESOURCE_MEM_64))
15508c2ecf20Sopenharmony_ci		idx = 2;
15518c2ecf20Sopenharmony_ci	else if (!(b_res[2].flags & IORESOURCE_MEM_64) &&
15528c2ecf20Sopenharmony_ci		 (b_res[2].flags & IORESOURCE_PREFETCH))
15538c2ecf20Sopenharmony_ci		idx = 2;
15548c2ecf20Sopenharmony_ci	else
15558c2ecf20Sopenharmony_ci		idx = 1;
15568c2ecf20Sopenharmony_ci
15578c2ecf20Sopenharmony_ci	r = &b_res[idx];
15588c2ecf20Sopenharmony_ci
15598c2ecf20Sopenharmony_ci	if (!r->parent)
15608c2ecf20Sopenharmony_ci		return;
15618c2ecf20Sopenharmony_ci
15628c2ecf20Sopenharmony_ci	/* If there are children, release them all */
15638c2ecf20Sopenharmony_ci	release_child_resources(r);
15648c2ecf20Sopenharmony_ci	if (!release_resource(r)) {
15658c2ecf20Sopenharmony_ci		type = old_flags = r->flags & PCI_RES_TYPE_MASK;
15668c2ecf20Sopenharmony_ci		pci_info(dev, "resource %d %pR released\n",
15678c2ecf20Sopenharmony_ci			 PCI_BRIDGE_RESOURCES + idx, r);
15688c2ecf20Sopenharmony_ci		/* Keep the old size */
15698c2ecf20Sopenharmony_ci		r->end = resource_size(r) - 1;
15708c2ecf20Sopenharmony_ci		r->start = 0;
15718c2ecf20Sopenharmony_ci		r->flags = 0;
15728c2ecf20Sopenharmony_ci
15738c2ecf20Sopenharmony_ci		/* Avoiding touch the one without PREF */
15748c2ecf20Sopenharmony_ci		if (type & IORESOURCE_PREFETCH)
15758c2ecf20Sopenharmony_ci			type = IORESOURCE_PREFETCH;
15768c2ecf20Sopenharmony_ci		__pci_setup_bridge(bus, type);
15778c2ecf20Sopenharmony_ci		/* For next child res under same bridge */
15788c2ecf20Sopenharmony_ci		r->flags = old_flags;
15798c2ecf20Sopenharmony_ci	}
15808c2ecf20Sopenharmony_ci}
15818c2ecf20Sopenharmony_ci
15828c2ecf20Sopenharmony_cienum release_type {
15838c2ecf20Sopenharmony_ci	leaf_only,
15848c2ecf20Sopenharmony_ci	whole_subtree,
15858c2ecf20Sopenharmony_ci};
15868c2ecf20Sopenharmony_ci
15878c2ecf20Sopenharmony_ci/*
15888c2ecf20Sopenharmony_ci * Try to release PCI bridge resources from leaf bridge, so we can allocate
15898c2ecf20Sopenharmony_ci * a larger window later.
15908c2ecf20Sopenharmony_ci */
15918c2ecf20Sopenharmony_cistatic void pci_bus_release_bridge_resources(struct pci_bus *bus,
15928c2ecf20Sopenharmony_ci					     unsigned long type,
15938c2ecf20Sopenharmony_ci					     enum release_type rel_type)
15948c2ecf20Sopenharmony_ci{
15958c2ecf20Sopenharmony_ci	struct pci_dev *dev;
15968c2ecf20Sopenharmony_ci	bool is_leaf_bridge = true;
15978c2ecf20Sopenharmony_ci
15988c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &bus->devices, bus_list) {
15998c2ecf20Sopenharmony_ci		struct pci_bus *b = dev->subordinate;
16008c2ecf20Sopenharmony_ci		if (!b)
16018c2ecf20Sopenharmony_ci			continue;
16028c2ecf20Sopenharmony_ci
16038c2ecf20Sopenharmony_ci		is_leaf_bridge = false;
16048c2ecf20Sopenharmony_ci
16058c2ecf20Sopenharmony_ci		if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI)
16068c2ecf20Sopenharmony_ci			continue;
16078c2ecf20Sopenharmony_ci
16088c2ecf20Sopenharmony_ci		if (rel_type == whole_subtree)
16098c2ecf20Sopenharmony_ci			pci_bus_release_bridge_resources(b, type,
16108c2ecf20Sopenharmony_ci						 whole_subtree);
16118c2ecf20Sopenharmony_ci	}
16128c2ecf20Sopenharmony_ci
16138c2ecf20Sopenharmony_ci	if (pci_is_root_bus(bus))
16148c2ecf20Sopenharmony_ci		return;
16158c2ecf20Sopenharmony_ci
16168c2ecf20Sopenharmony_ci	if ((bus->self->class >> 8) != PCI_CLASS_BRIDGE_PCI)
16178c2ecf20Sopenharmony_ci		return;
16188c2ecf20Sopenharmony_ci
16198c2ecf20Sopenharmony_ci	if ((rel_type == whole_subtree) || is_leaf_bridge)
16208c2ecf20Sopenharmony_ci		pci_bridge_release_resources(bus, type);
16218c2ecf20Sopenharmony_ci}
16228c2ecf20Sopenharmony_ci
16238c2ecf20Sopenharmony_cistatic void pci_bus_dump_res(struct pci_bus *bus)
16248c2ecf20Sopenharmony_ci{
16258c2ecf20Sopenharmony_ci	struct resource *res;
16268c2ecf20Sopenharmony_ci	int i;
16278c2ecf20Sopenharmony_ci
16288c2ecf20Sopenharmony_ci	pci_bus_for_each_resource(bus, res, i) {
16298c2ecf20Sopenharmony_ci		if (!res || !res->end || !res->flags)
16308c2ecf20Sopenharmony_ci			continue;
16318c2ecf20Sopenharmony_ci
16328c2ecf20Sopenharmony_ci		dev_info(&bus->dev, "resource %d %pR\n", i, res);
16338c2ecf20Sopenharmony_ci	}
16348c2ecf20Sopenharmony_ci}
16358c2ecf20Sopenharmony_ci
16368c2ecf20Sopenharmony_cistatic void pci_bus_dump_resources(struct pci_bus *bus)
16378c2ecf20Sopenharmony_ci{
16388c2ecf20Sopenharmony_ci	struct pci_bus *b;
16398c2ecf20Sopenharmony_ci	struct pci_dev *dev;
16408c2ecf20Sopenharmony_ci
16418c2ecf20Sopenharmony_ci
16428c2ecf20Sopenharmony_ci	pci_bus_dump_res(bus);
16438c2ecf20Sopenharmony_ci
16448c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &bus->devices, bus_list) {
16458c2ecf20Sopenharmony_ci		b = dev->subordinate;
16468c2ecf20Sopenharmony_ci		if (!b)
16478c2ecf20Sopenharmony_ci			continue;
16488c2ecf20Sopenharmony_ci
16498c2ecf20Sopenharmony_ci		pci_bus_dump_resources(b);
16508c2ecf20Sopenharmony_ci	}
16518c2ecf20Sopenharmony_ci}
16528c2ecf20Sopenharmony_ci
16538c2ecf20Sopenharmony_cistatic int pci_bus_get_depth(struct pci_bus *bus)
16548c2ecf20Sopenharmony_ci{
16558c2ecf20Sopenharmony_ci	int depth = 0;
16568c2ecf20Sopenharmony_ci	struct pci_bus *child_bus;
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci	list_for_each_entry(child_bus, &bus->children, node) {
16598c2ecf20Sopenharmony_ci		int ret;
16608c2ecf20Sopenharmony_ci
16618c2ecf20Sopenharmony_ci		ret = pci_bus_get_depth(child_bus);
16628c2ecf20Sopenharmony_ci		if (ret + 1 > depth)
16638c2ecf20Sopenharmony_ci			depth = ret + 1;
16648c2ecf20Sopenharmony_ci	}
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci	return depth;
16678c2ecf20Sopenharmony_ci}
16688c2ecf20Sopenharmony_ci
16698c2ecf20Sopenharmony_ci/*
16708c2ecf20Sopenharmony_ci * -1: undefined, will auto detect later
16718c2ecf20Sopenharmony_ci *  0: disabled by user
16728c2ecf20Sopenharmony_ci *  1: disabled by auto detect
16738c2ecf20Sopenharmony_ci *  2: enabled by user
16748c2ecf20Sopenharmony_ci *  3: enabled by auto detect
16758c2ecf20Sopenharmony_ci */
16768c2ecf20Sopenharmony_cienum enable_type {
16778c2ecf20Sopenharmony_ci	undefined = -1,
16788c2ecf20Sopenharmony_ci	user_disabled,
16798c2ecf20Sopenharmony_ci	auto_disabled,
16808c2ecf20Sopenharmony_ci	user_enabled,
16818c2ecf20Sopenharmony_ci	auto_enabled,
16828c2ecf20Sopenharmony_ci};
16838c2ecf20Sopenharmony_ci
16848c2ecf20Sopenharmony_cistatic enum enable_type pci_realloc_enable = undefined;
16858c2ecf20Sopenharmony_civoid __init pci_realloc_get_opt(char *str)
16868c2ecf20Sopenharmony_ci{
16878c2ecf20Sopenharmony_ci	if (!strncmp(str, "off", 3))
16888c2ecf20Sopenharmony_ci		pci_realloc_enable = user_disabled;
16898c2ecf20Sopenharmony_ci	else if (!strncmp(str, "on", 2))
16908c2ecf20Sopenharmony_ci		pci_realloc_enable = user_enabled;
16918c2ecf20Sopenharmony_ci}
16928c2ecf20Sopenharmony_cistatic bool pci_realloc_enabled(enum enable_type enable)
16938c2ecf20Sopenharmony_ci{
16948c2ecf20Sopenharmony_ci	return enable >= user_enabled;
16958c2ecf20Sopenharmony_ci}
16968c2ecf20Sopenharmony_ci
16978c2ecf20Sopenharmony_ci#if defined(CONFIG_PCI_IOV) && defined(CONFIG_PCI_REALLOC_ENABLE_AUTO)
16988c2ecf20Sopenharmony_cistatic int iov_resources_unassigned(struct pci_dev *dev, void *data)
16998c2ecf20Sopenharmony_ci{
17008c2ecf20Sopenharmony_ci	int i;
17018c2ecf20Sopenharmony_ci	bool *unassigned = data;
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {
17048c2ecf20Sopenharmony_ci		struct resource *r = &dev->resource[i + PCI_IOV_RESOURCES];
17058c2ecf20Sopenharmony_ci		struct pci_bus_region region;
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_ci		/* Not assigned or rejected by kernel? */
17088c2ecf20Sopenharmony_ci		if (!r->flags)
17098c2ecf20Sopenharmony_ci			continue;
17108c2ecf20Sopenharmony_ci
17118c2ecf20Sopenharmony_ci		pcibios_resource_to_bus(dev->bus, &region, r);
17128c2ecf20Sopenharmony_ci		if (!region.start) {
17138c2ecf20Sopenharmony_ci			*unassigned = true;
17148c2ecf20Sopenharmony_ci			return 1; /* Return early from pci_walk_bus() */
17158c2ecf20Sopenharmony_ci		}
17168c2ecf20Sopenharmony_ci	}
17178c2ecf20Sopenharmony_ci
17188c2ecf20Sopenharmony_ci	return 0;
17198c2ecf20Sopenharmony_ci}
17208c2ecf20Sopenharmony_ci
17218c2ecf20Sopenharmony_cistatic enum enable_type pci_realloc_detect(struct pci_bus *bus,
17228c2ecf20Sopenharmony_ci					   enum enable_type enable_local)
17238c2ecf20Sopenharmony_ci{
17248c2ecf20Sopenharmony_ci	bool unassigned = false;
17258c2ecf20Sopenharmony_ci	struct pci_host_bridge *host;
17268c2ecf20Sopenharmony_ci
17278c2ecf20Sopenharmony_ci	if (enable_local != undefined)
17288c2ecf20Sopenharmony_ci		return enable_local;
17298c2ecf20Sopenharmony_ci
17308c2ecf20Sopenharmony_ci	host = pci_find_host_bridge(bus);
17318c2ecf20Sopenharmony_ci	if (host->preserve_config)
17328c2ecf20Sopenharmony_ci		return auto_disabled;
17338c2ecf20Sopenharmony_ci
17348c2ecf20Sopenharmony_ci	pci_walk_bus(bus, iov_resources_unassigned, &unassigned);
17358c2ecf20Sopenharmony_ci	if (unassigned)
17368c2ecf20Sopenharmony_ci		return auto_enabled;
17378c2ecf20Sopenharmony_ci
17388c2ecf20Sopenharmony_ci	return enable_local;
17398c2ecf20Sopenharmony_ci}
17408c2ecf20Sopenharmony_ci#else
17418c2ecf20Sopenharmony_cistatic enum enable_type pci_realloc_detect(struct pci_bus *bus,
17428c2ecf20Sopenharmony_ci					   enum enable_type enable_local)
17438c2ecf20Sopenharmony_ci{
17448c2ecf20Sopenharmony_ci	return enable_local;
17458c2ecf20Sopenharmony_ci}
17468c2ecf20Sopenharmony_ci#endif
17478c2ecf20Sopenharmony_ci
17488c2ecf20Sopenharmony_ci/*
17498c2ecf20Sopenharmony_ci * First try will not touch PCI bridge res.
17508c2ecf20Sopenharmony_ci * Second and later try will clear small leaf bridge res.
17518c2ecf20Sopenharmony_ci * Will stop till to the max depth if can not find good one.
17528c2ecf20Sopenharmony_ci */
17538c2ecf20Sopenharmony_civoid pci_assign_unassigned_root_bus_resources(struct pci_bus *bus)
17548c2ecf20Sopenharmony_ci{
17558c2ecf20Sopenharmony_ci	LIST_HEAD(realloc_head);
17568c2ecf20Sopenharmony_ci	/* List of resources that want additional resources */
17578c2ecf20Sopenharmony_ci	struct list_head *add_list = NULL;
17588c2ecf20Sopenharmony_ci	int tried_times = 0;
17598c2ecf20Sopenharmony_ci	enum release_type rel_type = leaf_only;
17608c2ecf20Sopenharmony_ci	LIST_HEAD(fail_head);
17618c2ecf20Sopenharmony_ci	struct pci_dev_resource *fail_res;
17628c2ecf20Sopenharmony_ci	int pci_try_num = 1;
17638c2ecf20Sopenharmony_ci	enum enable_type enable_local;
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_ci	/* Don't realloc if asked to do so */
17668c2ecf20Sopenharmony_ci	enable_local = pci_realloc_detect(bus, pci_realloc_enable);
17678c2ecf20Sopenharmony_ci	if (pci_realloc_enabled(enable_local)) {
17688c2ecf20Sopenharmony_ci		int max_depth = pci_bus_get_depth(bus);
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci		pci_try_num = max_depth + 1;
17718c2ecf20Sopenharmony_ci		dev_info(&bus->dev, "max bus depth: %d pci_try_num: %d\n",
17728c2ecf20Sopenharmony_ci			 max_depth, pci_try_num);
17738c2ecf20Sopenharmony_ci	}
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_ciagain:
17768c2ecf20Sopenharmony_ci	/*
17778c2ecf20Sopenharmony_ci	 * Last try will use add_list, otherwise will try good to have as must
17788c2ecf20Sopenharmony_ci	 * have, so can realloc parent bridge resource
17798c2ecf20Sopenharmony_ci	 */
17808c2ecf20Sopenharmony_ci	if (tried_times + 1 == pci_try_num)
17818c2ecf20Sopenharmony_ci		add_list = &realloc_head;
17828c2ecf20Sopenharmony_ci	/*
17838c2ecf20Sopenharmony_ci	 * Depth first, calculate sizes and alignments of all subordinate buses.
17848c2ecf20Sopenharmony_ci	 */
17858c2ecf20Sopenharmony_ci	__pci_bus_size_bridges(bus, add_list);
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	/* Depth last, allocate resources and update the hardware. */
17888c2ecf20Sopenharmony_ci	__pci_bus_assign_resources(bus, add_list, &fail_head);
17898c2ecf20Sopenharmony_ci	if (add_list)
17908c2ecf20Sopenharmony_ci		BUG_ON(!list_empty(add_list));
17918c2ecf20Sopenharmony_ci	tried_times++;
17928c2ecf20Sopenharmony_ci
17938c2ecf20Sopenharmony_ci	/* Any device complain? */
17948c2ecf20Sopenharmony_ci	if (list_empty(&fail_head))
17958c2ecf20Sopenharmony_ci		goto dump;
17968c2ecf20Sopenharmony_ci
17978c2ecf20Sopenharmony_ci	if (tried_times >= pci_try_num) {
17988c2ecf20Sopenharmony_ci		if (enable_local == undefined)
17998c2ecf20Sopenharmony_ci			dev_info(&bus->dev, "Some PCI device resources are unassigned, try booting with pci=realloc\n");
18008c2ecf20Sopenharmony_ci		else if (enable_local == auto_enabled)
18018c2ecf20Sopenharmony_ci			dev_info(&bus->dev, "Automatically enabled pci realloc, if you have problem, try booting with pci=realloc=off\n");
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci		free_list(&fail_head);
18048c2ecf20Sopenharmony_ci		goto dump;
18058c2ecf20Sopenharmony_ci	}
18068c2ecf20Sopenharmony_ci
18078c2ecf20Sopenharmony_ci	dev_info(&bus->dev, "No. %d try to assign unassigned res\n",
18088c2ecf20Sopenharmony_ci		 tried_times + 1);
18098c2ecf20Sopenharmony_ci
18108c2ecf20Sopenharmony_ci	/* Third times and later will not check if it is leaf */
18118c2ecf20Sopenharmony_ci	if ((tried_times + 1) > 2)
18128c2ecf20Sopenharmony_ci		rel_type = whole_subtree;
18138c2ecf20Sopenharmony_ci
18148c2ecf20Sopenharmony_ci	/*
18158c2ecf20Sopenharmony_ci	 * Try to release leaf bridge's resources that doesn't fit resource of
18168c2ecf20Sopenharmony_ci	 * child device under that bridge.
18178c2ecf20Sopenharmony_ci	 */
18188c2ecf20Sopenharmony_ci	list_for_each_entry(fail_res, &fail_head, list)
18198c2ecf20Sopenharmony_ci		pci_bus_release_bridge_resources(fail_res->dev->bus,
18208c2ecf20Sopenharmony_ci						 fail_res->flags & PCI_RES_TYPE_MASK,
18218c2ecf20Sopenharmony_ci						 rel_type);
18228c2ecf20Sopenharmony_ci
18238c2ecf20Sopenharmony_ci	/* Restore size and flags */
18248c2ecf20Sopenharmony_ci	list_for_each_entry(fail_res, &fail_head, list) {
18258c2ecf20Sopenharmony_ci		struct resource *res = fail_res->res;
18268c2ecf20Sopenharmony_ci		int idx;
18278c2ecf20Sopenharmony_ci
18288c2ecf20Sopenharmony_ci		res->start = fail_res->start;
18298c2ecf20Sopenharmony_ci		res->end = fail_res->end;
18308c2ecf20Sopenharmony_ci		res->flags = fail_res->flags;
18318c2ecf20Sopenharmony_ci
18328c2ecf20Sopenharmony_ci		if (pci_is_bridge(fail_res->dev)) {
18338c2ecf20Sopenharmony_ci			idx = res - &fail_res->dev->resource[0];
18348c2ecf20Sopenharmony_ci			if (idx >= PCI_BRIDGE_RESOURCES &&
18358c2ecf20Sopenharmony_ci			    idx <= PCI_BRIDGE_RESOURCE_END)
18368c2ecf20Sopenharmony_ci				res->flags = 0;
18378c2ecf20Sopenharmony_ci		}
18388c2ecf20Sopenharmony_ci	}
18398c2ecf20Sopenharmony_ci	free_list(&fail_head);
18408c2ecf20Sopenharmony_ci
18418c2ecf20Sopenharmony_ci	goto again;
18428c2ecf20Sopenharmony_ci
18438c2ecf20Sopenharmony_cidump:
18448c2ecf20Sopenharmony_ci	/* Dump the resource on buses */
18458c2ecf20Sopenharmony_ci	pci_bus_dump_resources(bus);
18468c2ecf20Sopenharmony_ci}
18478c2ecf20Sopenharmony_ci
18488c2ecf20Sopenharmony_civoid __init pci_assign_unassigned_resources(void)
18498c2ecf20Sopenharmony_ci{
18508c2ecf20Sopenharmony_ci	struct pci_bus *root_bus;
18518c2ecf20Sopenharmony_ci
18528c2ecf20Sopenharmony_ci	list_for_each_entry(root_bus, &pci_root_buses, node) {
18538c2ecf20Sopenharmony_ci		pci_assign_unassigned_root_bus_resources(root_bus);
18548c2ecf20Sopenharmony_ci
18558c2ecf20Sopenharmony_ci		/* Make sure the root bridge has a companion ACPI device */
18568c2ecf20Sopenharmony_ci		if (ACPI_HANDLE(root_bus->bridge))
18578c2ecf20Sopenharmony_ci			acpi_ioapic_add(ACPI_HANDLE(root_bus->bridge));
18588c2ecf20Sopenharmony_ci	}
18598c2ecf20Sopenharmony_ci}
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_cistatic void adjust_bridge_window(struct pci_dev *bridge, struct resource *res,
18628c2ecf20Sopenharmony_ci				 struct list_head *add_list,
18638c2ecf20Sopenharmony_ci				 resource_size_t new_size)
18648c2ecf20Sopenharmony_ci{
18658c2ecf20Sopenharmony_ci	resource_size_t add_size, size = resource_size(res);
18668c2ecf20Sopenharmony_ci
18678c2ecf20Sopenharmony_ci	if (res->parent)
18688c2ecf20Sopenharmony_ci		return;
18698c2ecf20Sopenharmony_ci
18708c2ecf20Sopenharmony_ci	if (!new_size)
18718c2ecf20Sopenharmony_ci		return;
18728c2ecf20Sopenharmony_ci
18738c2ecf20Sopenharmony_ci	if (new_size > size) {
18748c2ecf20Sopenharmony_ci		add_size = new_size - size;
18758c2ecf20Sopenharmony_ci		pci_dbg(bridge, "bridge window %pR extended by %pa\n", res,
18768c2ecf20Sopenharmony_ci			&add_size);
18778c2ecf20Sopenharmony_ci	} else if (new_size < size) {
18788c2ecf20Sopenharmony_ci		add_size = size - new_size;
18798c2ecf20Sopenharmony_ci		pci_dbg(bridge, "bridge window %pR shrunken by %pa\n", res,
18808c2ecf20Sopenharmony_ci			&add_size);
18818c2ecf20Sopenharmony_ci	} else {
18828c2ecf20Sopenharmony_ci		return;
18838c2ecf20Sopenharmony_ci	}
18848c2ecf20Sopenharmony_ci
18858c2ecf20Sopenharmony_ci	res->end = res->start + new_size - 1;
18868c2ecf20Sopenharmony_ci	remove_from_list(add_list, res);
18878c2ecf20Sopenharmony_ci}
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_cistatic void remove_dev_resource(struct resource *avail, struct pci_dev *dev,
18908c2ecf20Sopenharmony_ci				struct resource *res)
18918c2ecf20Sopenharmony_ci{
18928c2ecf20Sopenharmony_ci	resource_size_t size, align, tmp;
18938c2ecf20Sopenharmony_ci
18948c2ecf20Sopenharmony_ci	size = resource_size(res);
18958c2ecf20Sopenharmony_ci	if (!size)
18968c2ecf20Sopenharmony_ci		return;
18978c2ecf20Sopenharmony_ci
18988c2ecf20Sopenharmony_ci	align = pci_resource_alignment(dev, res);
18998c2ecf20Sopenharmony_ci	align = align ? ALIGN(avail->start, align) - avail->start : 0;
19008c2ecf20Sopenharmony_ci	tmp = align + size;
19018c2ecf20Sopenharmony_ci	avail->start = min(avail->start + tmp, avail->end + 1);
19028c2ecf20Sopenharmony_ci}
19038c2ecf20Sopenharmony_ci
19048c2ecf20Sopenharmony_cistatic void remove_dev_resources(struct pci_dev *dev, struct resource *io,
19058c2ecf20Sopenharmony_ci				 struct resource *mmio,
19068c2ecf20Sopenharmony_ci				 struct resource *mmio_pref)
19078c2ecf20Sopenharmony_ci{
19088c2ecf20Sopenharmony_ci	int i;
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_ci	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
19118c2ecf20Sopenharmony_ci		struct resource *res = &dev->resource[i];
19128c2ecf20Sopenharmony_ci
19138c2ecf20Sopenharmony_ci		if (resource_type(res) == IORESOURCE_IO) {
19148c2ecf20Sopenharmony_ci			remove_dev_resource(io, dev, res);
19158c2ecf20Sopenharmony_ci		} else if (resource_type(res) == IORESOURCE_MEM) {
19168c2ecf20Sopenharmony_ci
19178c2ecf20Sopenharmony_ci			/*
19188c2ecf20Sopenharmony_ci			 * Make sure prefetchable memory is reduced from
19198c2ecf20Sopenharmony_ci			 * the correct resource. Specifically we put 32-bit
19208c2ecf20Sopenharmony_ci			 * prefetchable memory in non-prefetchable window
19218c2ecf20Sopenharmony_ci			 * if there is an 64-bit pretchable window.
19228c2ecf20Sopenharmony_ci			 *
19238c2ecf20Sopenharmony_ci			 * See comments in __pci_bus_size_bridges() for
19248c2ecf20Sopenharmony_ci			 * more information.
19258c2ecf20Sopenharmony_ci			 */
19268c2ecf20Sopenharmony_ci			if ((res->flags & IORESOURCE_PREFETCH) &&
19278c2ecf20Sopenharmony_ci			    ((res->flags & IORESOURCE_MEM_64) ==
19288c2ecf20Sopenharmony_ci			     (mmio_pref->flags & IORESOURCE_MEM_64)))
19298c2ecf20Sopenharmony_ci				remove_dev_resource(mmio_pref, dev, res);
19308c2ecf20Sopenharmony_ci			else
19318c2ecf20Sopenharmony_ci				remove_dev_resource(mmio, dev, res);
19328c2ecf20Sopenharmony_ci		}
19338c2ecf20Sopenharmony_ci	}
19348c2ecf20Sopenharmony_ci}
19358c2ecf20Sopenharmony_ci
19368c2ecf20Sopenharmony_ci/*
19378c2ecf20Sopenharmony_ci * io, mmio and mmio_pref contain the total amount of bridge window space
19388c2ecf20Sopenharmony_ci * available. This includes the minimal space needed to cover all the
19398c2ecf20Sopenharmony_ci * existing devices on the bus and the possible extra space that can be
19408c2ecf20Sopenharmony_ci * shared with the bridges.
19418c2ecf20Sopenharmony_ci */
19428c2ecf20Sopenharmony_cistatic void pci_bus_distribute_available_resources(struct pci_bus *bus,
19438c2ecf20Sopenharmony_ci					    struct list_head *add_list,
19448c2ecf20Sopenharmony_ci					    struct resource io,
19458c2ecf20Sopenharmony_ci					    struct resource mmio,
19468c2ecf20Sopenharmony_ci					    struct resource mmio_pref)
19478c2ecf20Sopenharmony_ci{
19488c2ecf20Sopenharmony_ci	unsigned int normal_bridges = 0, hotplug_bridges = 0;
19498c2ecf20Sopenharmony_ci	struct resource *io_res, *mmio_res, *mmio_pref_res;
19508c2ecf20Sopenharmony_ci	struct pci_dev *dev, *bridge = bus->self;
19518c2ecf20Sopenharmony_ci	resource_size_t io_per_b, mmio_per_b, mmio_pref_per_b, align;
19528c2ecf20Sopenharmony_ci
19538c2ecf20Sopenharmony_ci	io_res = &bridge->resource[PCI_BRIDGE_IO_WINDOW];
19548c2ecf20Sopenharmony_ci	mmio_res = &bridge->resource[PCI_BRIDGE_MEM_WINDOW];
19558c2ecf20Sopenharmony_ci	mmio_pref_res = &bridge->resource[PCI_BRIDGE_PREF_MEM_WINDOW];
19568c2ecf20Sopenharmony_ci
19578c2ecf20Sopenharmony_ci	/*
19588c2ecf20Sopenharmony_ci	 * The alignment of this bridge is yet to be considered, hence it must
19598c2ecf20Sopenharmony_ci	 * be done now before extending its bridge window.
19608c2ecf20Sopenharmony_ci	 */
19618c2ecf20Sopenharmony_ci	align = pci_resource_alignment(bridge, io_res);
19628c2ecf20Sopenharmony_ci	if (!io_res->parent && align)
19638c2ecf20Sopenharmony_ci		io.start = min(ALIGN(io.start, align), io.end + 1);
19648c2ecf20Sopenharmony_ci
19658c2ecf20Sopenharmony_ci	align = pci_resource_alignment(bridge, mmio_res);
19668c2ecf20Sopenharmony_ci	if (!mmio_res->parent && align)
19678c2ecf20Sopenharmony_ci		mmio.start = min(ALIGN(mmio.start, align), mmio.end + 1);
19688c2ecf20Sopenharmony_ci
19698c2ecf20Sopenharmony_ci	align = pci_resource_alignment(bridge, mmio_pref_res);
19708c2ecf20Sopenharmony_ci	if (!mmio_pref_res->parent && align)
19718c2ecf20Sopenharmony_ci		mmio_pref.start = min(ALIGN(mmio_pref.start, align),
19728c2ecf20Sopenharmony_ci			mmio_pref.end + 1);
19738c2ecf20Sopenharmony_ci
19748c2ecf20Sopenharmony_ci	/*
19758c2ecf20Sopenharmony_ci	 * Now that we have adjusted for alignment, update the bridge window
19768c2ecf20Sopenharmony_ci	 * resources to fill as much remaining resource space as possible.
19778c2ecf20Sopenharmony_ci	 */
19788c2ecf20Sopenharmony_ci	adjust_bridge_window(bridge, io_res, add_list, resource_size(&io));
19798c2ecf20Sopenharmony_ci	adjust_bridge_window(bridge, mmio_res, add_list, resource_size(&mmio));
19808c2ecf20Sopenharmony_ci	adjust_bridge_window(bridge, mmio_pref_res, add_list,
19818c2ecf20Sopenharmony_ci			     resource_size(&mmio_pref));
19828c2ecf20Sopenharmony_ci
19838c2ecf20Sopenharmony_ci	/*
19848c2ecf20Sopenharmony_ci	 * Calculate how many hotplug bridges and normal bridges there
19858c2ecf20Sopenharmony_ci	 * are on this bus.  We will distribute the additional available
19868c2ecf20Sopenharmony_ci	 * resources between hotplug bridges.
19878c2ecf20Sopenharmony_ci	 */
19888c2ecf20Sopenharmony_ci	for_each_pci_bridge(dev, bus) {
19898c2ecf20Sopenharmony_ci		if (dev->is_hotplug_bridge)
19908c2ecf20Sopenharmony_ci			hotplug_bridges++;
19918c2ecf20Sopenharmony_ci		else
19928c2ecf20Sopenharmony_ci			normal_bridges++;
19938c2ecf20Sopenharmony_ci	}
19948c2ecf20Sopenharmony_ci
19958c2ecf20Sopenharmony_ci	if (!(hotplug_bridges + normal_bridges))
19968c2ecf20Sopenharmony_ci		return;
19978c2ecf20Sopenharmony_ci
19988c2ecf20Sopenharmony_ci	/*
19998c2ecf20Sopenharmony_ci	 * Calculate the amount of space we can forward from "bus" to any
20008c2ecf20Sopenharmony_ci	 * downstream buses, i.e., the space left over after assigning the
20018c2ecf20Sopenharmony_ci	 * BARs and windows on "bus".
20028c2ecf20Sopenharmony_ci	 */
20038c2ecf20Sopenharmony_ci	list_for_each_entry(dev, &bus->devices, bus_list) {
20048c2ecf20Sopenharmony_ci		if (!dev->is_virtfn)
20058c2ecf20Sopenharmony_ci			remove_dev_resources(dev, &io, &mmio, &mmio_pref);
20068c2ecf20Sopenharmony_ci	}
20078c2ecf20Sopenharmony_ci
20088c2ecf20Sopenharmony_ci	/*
20098c2ecf20Sopenharmony_ci	 * If there is at least one hotplug bridge on this bus it gets all
20108c2ecf20Sopenharmony_ci	 * the extra resource space that was left after the reductions
20118c2ecf20Sopenharmony_ci	 * above.
20128c2ecf20Sopenharmony_ci	 *
20138c2ecf20Sopenharmony_ci	 * If there are no hotplug bridges the extra resource space is
20148c2ecf20Sopenharmony_ci	 * split between non-hotplug bridges. This is to allow possible
20158c2ecf20Sopenharmony_ci	 * hotplug bridges below them to get the extra space as well.
20168c2ecf20Sopenharmony_ci	 */
20178c2ecf20Sopenharmony_ci	if (hotplug_bridges) {
20188c2ecf20Sopenharmony_ci		io_per_b = div64_ul(resource_size(&io), hotplug_bridges);
20198c2ecf20Sopenharmony_ci		mmio_per_b = div64_ul(resource_size(&mmio), hotplug_bridges);
20208c2ecf20Sopenharmony_ci		mmio_pref_per_b = div64_ul(resource_size(&mmio_pref),
20218c2ecf20Sopenharmony_ci					   hotplug_bridges);
20228c2ecf20Sopenharmony_ci	} else {
20238c2ecf20Sopenharmony_ci		io_per_b = div64_ul(resource_size(&io), normal_bridges);
20248c2ecf20Sopenharmony_ci		mmio_per_b = div64_ul(resource_size(&mmio), normal_bridges);
20258c2ecf20Sopenharmony_ci		mmio_pref_per_b = div64_ul(resource_size(&mmio_pref),
20268c2ecf20Sopenharmony_ci					   normal_bridges);
20278c2ecf20Sopenharmony_ci	}
20288c2ecf20Sopenharmony_ci
20298c2ecf20Sopenharmony_ci	for_each_pci_bridge(dev, bus) {
20308c2ecf20Sopenharmony_ci		struct resource *res;
20318c2ecf20Sopenharmony_ci		struct pci_bus *b;
20328c2ecf20Sopenharmony_ci
20338c2ecf20Sopenharmony_ci		b = dev->subordinate;
20348c2ecf20Sopenharmony_ci		if (!b)
20358c2ecf20Sopenharmony_ci			continue;
20368c2ecf20Sopenharmony_ci		if (hotplug_bridges && !dev->is_hotplug_bridge)
20378c2ecf20Sopenharmony_ci			continue;
20388c2ecf20Sopenharmony_ci
20398c2ecf20Sopenharmony_ci		res = &dev->resource[PCI_BRIDGE_IO_WINDOW];
20408c2ecf20Sopenharmony_ci
20418c2ecf20Sopenharmony_ci		/*
20428c2ecf20Sopenharmony_ci		 * Make sure the split resource space is properly aligned
20438c2ecf20Sopenharmony_ci		 * for bridge windows (align it down to avoid going above
20448c2ecf20Sopenharmony_ci		 * what is available).
20458c2ecf20Sopenharmony_ci		 */
20468c2ecf20Sopenharmony_ci		align = pci_resource_alignment(dev, res);
20478c2ecf20Sopenharmony_ci		io.end = align ? io.start + ALIGN_DOWN(io_per_b, align) - 1
20488c2ecf20Sopenharmony_ci			       : io.start + io_per_b - 1;
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_ci		/*
20518c2ecf20Sopenharmony_ci		 * The x_per_b holds the extra resource space that can be
20528c2ecf20Sopenharmony_ci		 * added for each bridge but there is the minimal already
20538c2ecf20Sopenharmony_ci		 * reserved as well so adjust x.start down accordingly to
20548c2ecf20Sopenharmony_ci		 * cover the whole space.
20558c2ecf20Sopenharmony_ci		 */
20568c2ecf20Sopenharmony_ci		io.start -= resource_size(res);
20578c2ecf20Sopenharmony_ci
20588c2ecf20Sopenharmony_ci		res = &dev->resource[PCI_BRIDGE_MEM_WINDOW];
20598c2ecf20Sopenharmony_ci		align = pci_resource_alignment(dev, res);
20608c2ecf20Sopenharmony_ci		mmio.end = align ? mmio.start + ALIGN_DOWN(mmio_per_b, align) - 1
20618c2ecf20Sopenharmony_ci				 : mmio.start + mmio_per_b - 1;
20628c2ecf20Sopenharmony_ci		mmio.start -= resource_size(res);
20638c2ecf20Sopenharmony_ci
20648c2ecf20Sopenharmony_ci		res = &dev->resource[PCI_BRIDGE_PREF_MEM_WINDOW];
20658c2ecf20Sopenharmony_ci		align = pci_resource_alignment(dev, res);
20668c2ecf20Sopenharmony_ci		mmio_pref.end = align ? mmio_pref.start +
20678c2ecf20Sopenharmony_ci					ALIGN_DOWN(mmio_pref_per_b, align) - 1
20688c2ecf20Sopenharmony_ci				      : mmio_pref.start + mmio_pref_per_b - 1;
20698c2ecf20Sopenharmony_ci		mmio_pref.start -= resource_size(res);
20708c2ecf20Sopenharmony_ci
20718c2ecf20Sopenharmony_ci		pci_bus_distribute_available_resources(b, add_list, io, mmio,
20728c2ecf20Sopenharmony_ci						       mmio_pref);
20738c2ecf20Sopenharmony_ci
20748c2ecf20Sopenharmony_ci		io.start += io.end + 1;
20758c2ecf20Sopenharmony_ci		mmio.start += mmio.end + 1;
20768c2ecf20Sopenharmony_ci		mmio_pref.start += mmio_pref.end + 1;
20778c2ecf20Sopenharmony_ci	}
20788c2ecf20Sopenharmony_ci}
20798c2ecf20Sopenharmony_ci
20808c2ecf20Sopenharmony_cistatic void pci_bridge_distribute_available_resources(struct pci_dev *bridge,
20818c2ecf20Sopenharmony_ci						     struct list_head *add_list)
20828c2ecf20Sopenharmony_ci{
20838c2ecf20Sopenharmony_ci	struct resource available_io, available_mmio, available_mmio_pref;
20848c2ecf20Sopenharmony_ci
20858c2ecf20Sopenharmony_ci	if (!bridge->is_hotplug_bridge)
20868c2ecf20Sopenharmony_ci		return;
20878c2ecf20Sopenharmony_ci
20888c2ecf20Sopenharmony_ci	/* Take the initial extra resources from the hotplug port */
20898c2ecf20Sopenharmony_ci	available_io = bridge->resource[PCI_BRIDGE_IO_WINDOW];
20908c2ecf20Sopenharmony_ci	available_mmio = bridge->resource[PCI_BRIDGE_MEM_WINDOW];
20918c2ecf20Sopenharmony_ci	available_mmio_pref = bridge->resource[PCI_BRIDGE_PREF_MEM_WINDOW];
20928c2ecf20Sopenharmony_ci
20938c2ecf20Sopenharmony_ci	pci_bus_distribute_available_resources(bridge->subordinate,
20948c2ecf20Sopenharmony_ci					       add_list, available_io,
20958c2ecf20Sopenharmony_ci					       available_mmio,
20968c2ecf20Sopenharmony_ci					       available_mmio_pref);
20978c2ecf20Sopenharmony_ci}
20988c2ecf20Sopenharmony_ci
20998c2ecf20Sopenharmony_civoid pci_assign_unassigned_bridge_resources(struct pci_dev *bridge)
21008c2ecf20Sopenharmony_ci{
21018c2ecf20Sopenharmony_ci	struct pci_bus *parent = bridge->subordinate;
21028c2ecf20Sopenharmony_ci	/* List of resources that want additional resources */
21038c2ecf20Sopenharmony_ci	LIST_HEAD(add_list);
21048c2ecf20Sopenharmony_ci
21058c2ecf20Sopenharmony_ci	int tried_times = 0;
21068c2ecf20Sopenharmony_ci	LIST_HEAD(fail_head);
21078c2ecf20Sopenharmony_ci	struct pci_dev_resource *fail_res;
21088c2ecf20Sopenharmony_ci	int retval;
21098c2ecf20Sopenharmony_ci
21108c2ecf20Sopenharmony_ciagain:
21118c2ecf20Sopenharmony_ci	__pci_bus_size_bridges(parent, &add_list);
21128c2ecf20Sopenharmony_ci
21138c2ecf20Sopenharmony_ci	/*
21148c2ecf20Sopenharmony_ci	 * Distribute remaining resources (if any) equally between hotplug
21158c2ecf20Sopenharmony_ci	 * bridges below.  This makes it possible to extend the hierarchy
21168c2ecf20Sopenharmony_ci	 * later without running out of resources.
21178c2ecf20Sopenharmony_ci	 */
21188c2ecf20Sopenharmony_ci	pci_bridge_distribute_available_resources(bridge, &add_list);
21198c2ecf20Sopenharmony_ci
21208c2ecf20Sopenharmony_ci	__pci_bridge_assign_resources(bridge, &add_list, &fail_head);
21218c2ecf20Sopenharmony_ci	BUG_ON(!list_empty(&add_list));
21228c2ecf20Sopenharmony_ci	tried_times++;
21238c2ecf20Sopenharmony_ci
21248c2ecf20Sopenharmony_ci	if (list_empty(&fail_head))
21258c2ecf20Sopenharmony_ci		goto enable_all;
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci	if (tried_times >= 2) {
21288c2ecf20Sopenharmony_ci		/* Still fail, don't need to try more */
21298c2ecf20Sopenharmony_ci		free_list(&fail_head);
21308c2ecf20Sopenharmony_ci		goto enable_all;
21318c2ecf20Sopenharmony_ci	}
21328c2ecf20Sopenharmony_ci
21338c2ecf20Sopenharmony_ci	printk(KERN_DEBUG "PCI: No. %d try to assign unassigned res\n",
21348c2ecf20Sopenharmony_ci			 tried_times + 1);
21358c2ecf20Sopenharmony_ci
21368c2ecf20Sopenharmony_ci	/*
21378c2ecf20Sopenharmony_ci	 * Try to release leaf bridge's resources that aren't big enough
21388c2ecf20Sopenharmony_ci	 * to contain child device resources.
21398c2ecf20Sopenharmony_ci	 */
21408c2ecf20Sopenharmony_ci	list_for_each_entry(fail_res, &fail_head, list)
21418c2ecf20Sopenharmony_ci		pci_bus_release_bridge_resources(fail_res->dev->bus,
21428c2ecf20Sopenharmony_ci						 fail_res->flags & PCI_RES_TYPE_MASK,
21438c2ecf20Sopenharmony_ci						 whole_subtree);
21448c2ecf20Sopenharmony_ci
21458c2ecf20Sopenharmony_ci	/* Restore size and flags */
21468c2ecf20Sopenharmony_ci	list_for_each_entry(fail_res, &fail_head, list) {
21478c2ecf20Sopenharmony_ci		struct resource *res = fail_res->res;
21488c2ecf20Sopenharmony_ci		int idx;
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_ci		res->start = fail_res->start;
21518c2ecf20Sopenharmony_ci		res->end = fail_res->end;
21528c2ecf20Sopenharmony_ci		res->flags = fail_res->flags;
21538c2ecf20Sopenharmony_ci
21548c2ecf20Sopenharmony_ci		if (pci_is_bridge(fail_res->dev)) {
21558c2ecf20Sopenharmony_ci			idx = res - &fail_res->dev->resource[0];
21568c2ecf20Sopenharmony_ci			if (idx >= PCI_BRIDGE_RESOURCES &&
21578c2ecf20Sopenharmony_ci			    idx <= PCI_BRIDGE_RESOURCE_END)
21588c2ecf20Sopenharmony_ci				res->flags = 0;
21598c2ecf20Sopenharmony_ci		}
21608c2ecf20Sopenharmony_ci	}
21618c2ecf20Sopenharmony_ci	free_list(&fail_head);
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_ci	goto again;
21648c2ecf20Sopenharmony_ci
21658c2ecf20Sopenharmony_cienable_all:
21668c2ecf20Sopenharmony_ci	retval = pci_reenable_device(bridge);
21678c2ecf20Sopenharmony_ci	if (retval)
21688c2ecf20Sopenharmony_ci		pci_err(bridge, "Error reenabling bridge (%d)\n", retval);
21698c2ecf20Sopenharmony_ci	pci_set_master(bridge);
21708c2ecf20Sopenharmony_ci}
21718c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_assign_unassigned_bridge_resources);
21728c2ecf20Sopenharmony_ci
21738c2ecf20Sopenharmony_ciint pci_reassign_bridge_resources(struct pci_dev *bridge, unsigned long type)
21748c2ecf20Sopenharmony_ci{
21758c2ecf20Sopenharmony_ci	struct pci_dev_resource *dev_res;
21768c2ecf20Sopenharmony_ci	struct pci_dev *next;
21778c2ecf20Sopenharmony_ci	LIST_HEAD(saved);
21788c2ecf20Sopenharmony_ci	LIST_HEAD(added);
21798c2ecf20Sopenharmony_ci	LIST_HEAD(failed);
21808c2ecf20Sopenharmony_ci	unsigned int i;
21818c2ecf20Sopenharmony_ci	int ret;
21828c2ecf20Sopenharmony_ci
21838c2ecf20Sopenharmony_ci	down_read(&pci_bus_sem);
21848c2ecf20Sopenharmony_ci
21858c2ecf20Sopenharmony_ci	/* Walk to the root hub, releasing bridge BARs when possible */
21868c2ecf20Sopenharmony_ci	next = bridge;
21878c2ecf20Sopenharmony_ci	do {
21888c2ecf20Sopenharmony_ci		bridge = next;
21898c2ecf20Sopenharmony_ci		for (i = PCI_BRIDGE_RESOURCES; i < PCI_BRIDGE_RESOURCE_END;
21908c2ecf20Sopenharmony_ci		     i++) {
21918c2ecf20Sopenharmony_ci			struct resource *res = &bridge->resource[i];
21928c2ecf20Sopenharmony_ci
21938c2ecf20Sopenharmony_ci			if ((res->flags ^ type) & PCI_RES_TYPE_MASK)
21948c2ecf20Sopenharmony_ci				continue;
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_ci			/* Ignore BARs which are still in use */
21978c2ecf20Sopenharmony_ci			if (res->child)
21988c2ecf20Sopenharmony_ci				continue;
21998c2ecf20Sopenharmony_ci
22008c2ecf20Sopenharmony_ci			ret = add_to_list(&saved, bridge, res, 0, 0);
22018c2ecf20Sopenharmony_ci			if (ret)
22028c2ecf20Sopenharmony_ci				goto cleanup;
22038c2ecf20Sopenharmony_ci
22048c2ecf20Sopenharmony_ci			pci_info(bridge, "BAR %d: releasing %pR\n",
22058c2ecf20Sopenharmony_ci				 i, res);
22068c2ecf20Sopenharmony_ci
22078c2ecf20Sopenharmony_ci			if (res->parent)
22088c2ecf20Sopenharmony_ci				release_resource(res);
22098c2ecf20Sopenharmony_ci			res->start = 0;
22108c2ecf20Sopenharmony_ci			res->end = 0;
22118c2ecf20Sopenharmony_ci			break;
22128c2ecf20Sopenharmony_ci		}
22138c2ecf20Sopenharmony_ci		if (i == PCI_BRIDGE_RESOURCE_END)
22148c2ecf20Sopenharmony_ci			break;
22158c2ecf20Sopenharmony_ci
22168c2ecf20Sopenharmony_ci		next = bridge->bus ? bridge->bus->self : NULL;
22178c2ecf20Sopenharmony_ci	} while (next);
22188c2ecf20Sopenharmony_ci
22198c2ecf20Sopenharmony_ci	if (list_empty(&saved)) {
22208c2ecf20Sopenharmony_ci		up_read(&pci_bus_sem);
22218c2ecf20Sopenharmony_ci		return -ENOENT;
22228c2ecf20Sopenharmony_ci	}
22238c2ecf20Sopenharmony_ci
22248c2ecf20Sopenharmony_ci	__pci_bus_size_bridges(bridge->subordinate, &added);
22258c2ecf20Sopenharmony_ci	__pci_bridge_assign_resources(bridge, &added, &failed);
22268c2ecf20Sopenharmony_ci	BUG_ON(!list_empty(&added));
22278c2ecf20Sopenharmony_ci
22288c2ecf20Sopenharmony_ci	if (!list_empty(&failed)) {
22298c2ecf20Sopenharmony_ci		ret = -ENOSPC;
22308c2ecf20Sopenharmony_ci		goto cleanup;
22318c2ecf20Sopenharmony_ci	}
22328c2ecf20Sopenharmony_ci
22338c2ecf20Sopenharmony_ci	list_for_each_entry(dev_res, &saved, list) {
22348c2ecf20Sopenharmony_ci		/* Skip the bridge we just assigned resources for */
22358c2ecf20Sopenharmony_ci		if (bridge == dev_res->dev)
22368c2ecf20Sopenharmony_ci			continue;
22378c2ecf20Sopenharmony_ci
22388c2ecf20Sopenharmony_ci		bridge = dev_res->dev;
22398c2ecf20Sopenharmony_ci		pci_setup_bridge(bridge->subordinate);
22408c2ecf20Sopenharmony_ci	}
22418c2ecf20Sopenharmony_ci
22428c2ecf20Sopenharmony_ci	free_list(&saved);
22438c2ecf20Sopenharmony_ci	up_read(&pci_bus_sem);
22448c2ecf20Sopenharmony_ci	return 0;
22458c2ecf20Sopenharmony_ci
22468c2ecf20Sopenharmony_cicleanup:
22478c2ecf20Sopenharmony_ci	/* Restore size and flags */
22488c2ecf20Sopenharmony_ci	list_for_each_entry(dev_res, &failed, list) {
22498c2ecf20Sopenharmony_ci		struct resource *res = dev_res->res;
22508c2ecf20Sopenharmony_ci
22518c2ecf20Sopenharmony_ci		res->start = dev_res->start;
22528c2ecf20Sopenharmony_ci		res->end = dev_res->end;
22538c2ecf20Sopenharmony_ci		res->flags = dev_res->flags;
22548c2ecf20Sopenharmony_ci	}
22558c2ecf20Sopenharmony_ci	free_list(&failed);
22568c2ecf20Sopenharmony_ci
22578c2ecf20Sopenharmony_ci	/* Revert to the old configuration */
22588c2ecf20Sopenharmony_ci	list_for_each_entry(dev_res, &saved, list) {
22598c2ecf20Sopenharmony_ci		struct resource *res = dev_res->res;
22608c2ecf20Sopenharmony_ci
22618c2ecf20Sopenharmony_ci		bridge = dev_res->dev;
22628c2ecf20Sopenharmony_ci		i = res - bridge->resource;
22638c2ecf20Sopenharmony_ci
22648c2ecf20Sopenharmony_ci		res->start = dev_res->start;
22658c2ecf20Sopenharmony_ci		res->end = dev_res->end;
22668c2ecf20Sopenharmony_ci		res->flags = dev_res->flags;
22678c2ecf20Sopenharmony_ci
22688c2ecf20Sopenharmony_ci		pci_claim_resource(bridge, i);
22698c2ecf20Sopenharmony_ci		pci_setup_bridge(bridge->subordinate);
22708c2ecf20Sopenharmony_ci	}
22718c2ecf20Sopenharmony_ci	free_list(&saved);
22728c2ecf20Sopenharmony_ci	up_read(&pci_bus_sem);
22738c2ecf20Sopenharmony_ci
22748c2ecf20Sopenharmony_ci	return ret;
22758c2ecf20Sopenharmony_ci}
22768c2ecf20Sopenharmony_ci
22778c2ecf20Sopenharmony_civoid pci_assign_unassigned_bus_resources(struct pci_bus *bus)
22788c2ecf20Sopenharmony_ci{
22798c2ecf20Sopenharmony_ci	struct pci_dev *dev;
22808c2ecf20Sopenharmony_ci	/* List of resources that want additional resources */
22818c2ecf20Sopenharmony_ci	LIST_HEAD(add_list);
22828c2ecf20Sopenharmony_ci
22838c2ecf20Sopenharmony_ci	down_read(&pci_bus_sem);
22848c2ecf20Sopenharmony_ci	for_each_pci_bridge(dev, bus)
22858c2ecf20Sopenharmony_ci		if (pci_has_subordinate(dev))
22868c2ecf20Sopenharmony_ci			__pci_bus_size_bridges(dev->subordinate, &add_list);
22878c2ecf20Sopenharmony_ci	up_read(&pci_bus_sem);
22888c2ecf20Sopenharmony_ci	__pci_bus_assign_resources(bus, &add_list, NULL);
22898c2ecf20Sopenharmony_ci	BUG_ON(!list_empty(&add_list));
22908c2ecf20Sopenharmony_ci}
22918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pci_assign_unassigned_bus_resources);
2292