162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *	Low-Level PCI Access for i386 machines
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 1993, 1994 Drew Eckhardt
662306a36Sopenharmony_ci *      Visionary Computing
762306a36Sopenharmony_ci *      (Unix and Linux consulting and custom programming)
862306a36Sopenharmony_ci *      Drew@Colorado.EDU
962306a36Sopenharmony_ci *      +1 (303) 786-7975
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Drew's work was sponsored by:
1262306a36Sopenharmony_ci *	iX Multiuser Multitasking Magazine
1362306a36Sopenharmony_ci *	Hannover, Germany
1462306a36Sopenharmony_ci *	hm@ix.de
1562306a36Sopenharmony_ci *
1662306a36Sopenharmony_ci * Copyright 1997--2000 Martin Mares <mj@ucw.cz>
1762306a36Sopenharmony_ci *
1862306a36Sopenharmony_ci * For more information, please consult the following manuals (look at
1962306a36Sopenharmony_ci * http://www.pcisig.com/ for how to get them):
2062306a36Sopenharmony_ci *
2162306a36Sopenharmony_ci * PCI BIOS Specification
2262306a36Sopenharmony_ci * PCI Local Bus Specification
2362306a36Sopenharmony_ci * PCI to PCI Bridge Specification
2462306a36Sopenharmony_ci * PCI System Design Guide
2562306a36Sopenharmony_ci *
2662306a36Sopenharmony_ci */
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci#include <linux/types.h>
2962306a36Sopenharmony_ci#include <linux/kernel.h>
3062306a36Sopenharmony_ci#include <linux/export.h>
3162306a36Sopenharmony_ci#include <linux/pci.h>
3262306a36Sopenharmony_ci#include <linux/init.h>
3362306a36Sopenharmony_ci#include <linux/ioport.h>
3462306a36Sopenharmony_ci#include <linux/errno.h>
3562306a36Sopenharmony_ci#include <linux/memblock.h>
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#include <asm/memtype.h>
3862306a36Sopenharmony_ci#include <asm/e820/api.h>
3962306a36Sopenharmony_ci#include <asm/pci_x86.h>
4062306a36Sopenharmony_ci#include <asm/io_apic.h>
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/*
4462306a36Sopenharmony_ci * This list of dynamic mappings is for temporarily maintaining
4562306a36Sopenharmony_ci * original BIOS BAR addresses for possible reinstatement.
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_cistruct pcibios_fwaddrmap {
4862306a36Sopenharmony_ci	struct list_head list;
4962306a36Sopenharmony_ci	struct pci_dev *dev;
5062306a36Sopenharmony_ci	resource_size_t fw_addr[DEVICE_COUNT_RESOURCE];
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic LIST_HEAD(pcibios_fwaddrmappings);
5462306a36Sopenharmony_cistatic DEFINE_SPINLOCK(pcibios_fwaddrmap_lock);
5562306a36Sopenharmony_cistatic bool pcibios_fw_addr_done;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/* Must be called with 'pcibios_fwaddrmap_lock' lock held. */
5862306a36Sopenharmony_cistatic struct pcibios_fwaddrmap *pcibios_fwaddrmap_lookup(struct pci_dev *dev)
5962306a36Sopenharmony_ci{
6062306a36Sopenharmony_ci	struct pcibios_fwaddrmap *map;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	lockdep_assert_held(&pcibios_fwaddrmap_lock);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	list_for_each_entry(map, &pcibios_fwaddrmappings, list)
6562306a36Sopenharmony_ci		if (map->dev == dev)
6662306a36Sopenharmony_ci			return map;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	return NULL;
6962306a36Sopenharmony_ci}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistatic void
7262306a36Sopenharmony_cipcibios_save_fw_addr(struct pci_dev *dev, int idx, resource_size_t fw_addr)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	unsigned long flags;
7562306a36Sopenharmony_ci	struct pcibios_fwaddrmap *map;
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	if (pcibios_fw_addr_done)
7862306a36Sopenharmony_ci		return;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
8162306a36Sopenharmony_ci	map = pcibios_fwaddrmap_lookup(dev);
8262306a36Sopenharmony_ci	if (!map) {
8362306a36Sopenharmony_ci		spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags);
8462306a36Sopenharmony_ci		map = kzalloc(sizeof(*map), GFP_KERNEL);
8562306a36Sopenharmony_ci		if (!map)
8662306a36Sopenharmony_ci			return;
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci		map->dev = pci_dev_get(dev);
8962306a36Sopenharmony_ci		map->fw_addr[idx] = fw_addr;
9062306a36Sopenharmony_ci		INIT_LIST_HEAD(&map->list);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci		spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
9362306a36Sopenharmony_ci		list_add_tail(&map->list, &pcibios_fwaddrmappings);
9462306a36Sopenharmony_ci	} else
9562306a36Sopenharmony_ci		map->fw_addr[idx] = fw_addr;
9662306a36Sopenharmony_ci	spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags);
9762306a36Sopenharmony_ci}
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ciresource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx)
10062306a36Sopenharmony_ci{
10162306a36Sopenharmony_ci	unsigned long flags;
10262306a36Sopenharmony_ci	struct pcibios_fwaddrmap *map;
10362306a36Sopenharmony_ci	resource_size_t fw_addr = 0;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	if (pcibios_fw_addr_done)
10662306a36Sopenharmony_ci		return 0;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
10962306a36Sopenharmony_ci	map = pcibios_fwaddrmap_lookup(dev);
11062306a36Sopenharmony_ci	if (map)
11162306a36Sopenharmony_ci		fw_addr = map->fw_addr[idx];
11262306a36Sopenharmony_ci	spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	return fw_addr;
11562306a36Sopenharmony_ci}
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_cistatic void __init pcibios_fw_addr_list_del(void)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	unsigned long flags;
12062306a36Sopenharmony_ci	struct pcibios_fwaddrmap *entry, *next;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	spin_lock_irqsave(&pcibios_fwaddrmap_lock, flags);
12362306a36Sopenharmony_ci	list_for_each_entry_safe(entry, next, &pcibios_fwaddrmappings, list) {
12462306a36Sopenharmony_ci		list_del(&entry->list);
12562306a36Sopenharmony_ci		pci_dev_put(entry->dev);
12662306a36Sopenharmony_ci		kfree(entry);
12762306a36Sopenharmony_ci	}
12862306a36Sopenharmony_ci	spin_unlock_irqrestore(&pcibios_fwaddrmap_lock, flags);
12962306a36Sopenharmony_ci	pcibios_fw_addr_done = true;
13062306a36Sopenharmony_ci}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_cistatic int
13362306a36Sopenharmony_ciskip_isa_ioresource_align(struct pci_dev *dev) {
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	if ((pci_probe & PCI_CAN_SKIP_ISA_ALIGN) &&
13662306a36Sopenharmony_ci	    !(dev->bus->bridge_ctl & PCI_BRIDGE_CTL_ISA))
13762306a36Sopenharmony_ci		return 1;
13862306a36Sopenharmony_ci	return 0;
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci/*
14262306a36Sopenharmony_ci * We need to avoid collisions with `mirrored' VGA ports
14362306a36Sopenharmony_ci * and other strange ISA hardware, so we always want the
14462306a36Sopenharmony_ci * addresses to be allocated in the 0x000-0x0ff region
14562306a36Sopenharmony_ci * modulo 0x400.
14662306a36Sopenharmony_ci *
14762306a36Sopenharmony_ci * Why? Because some silly external IO cards only decode
14862306a36Sopenharmony_ci * the low 10 bits of the IO address. The 0x00-0xff region
14962306a36Sopenharmony_ci * is reserved for motherboard devices that decode all 16
15062306a36Sopenharmony_ci * bits, so it's ok to allocate at, say, 0x2800-0x28ff,
15162306a36Sopenharmony_ci * but we want to try to avoid allocating at 0x2900-0x2bff
15262306a36Sopenharmony_ci * which might have be mirrored at 0x0100-0x03ff..
15362306a36Sopenharmony_ci */
15462306a36Sopenharmony_ciresource_size_t
15562306a36Sopenharmony_cipcibios_align_resource(void *data, const struct resource *res,
15662306a36Sopenharmony_ci			resource_size_t size, resource_size_t align)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	struct pci_dev *dev = data;
15962306a36Sopenharmony_ci	resource_size_t start = res->start;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	if (res->flags & IORESOURCE_IO) {
16262306a36Sopenharmony_ci		if (skip_isa_ioresource_align(dev))
16362306a36Sopenharmony_ci			return start;
16462306a36Sopenharmony_ci		if (start & 0x300)
16562306a36Sopenharmony_ci			start = (start + 0x3ff) & ~0x3ff;
16662306a36Sopenharmony_ci	} else if (res->flags & IORESOURCE_MEM) {
16762306a36Sopenharmony_ci		/* The low 1MB range is reserved for ISA cards */
16862306a36Sopenharmony_ci		if (start < BIOS_END)
16962306a36Sopenharmony_ci			start = BIOS_END;
17062306a36Sopenharmony_ci	}
17162306a36Sopenharmony_ci	return start;
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ciEXPORT_SYMBOL(pcibios_align_resource);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci/*
17662306a36Sopenharmony_ci *  Handle resources of PCI devices.  If the world were perfect, we could
17762306a36Sopenharmony_ci *  just allocate all the resource regions and do nothing more.  It isn't.
17862306a36Sopenharmony_ci *  On the other hand, we cannot just re-allocate all devices, as it would
17962306a36Sopenharmony_ci *  require us to know lots of host bridge internals.  So we attempt to
18062306a36Sopenharmony_ci *  keep as much of the original configuration as possible, but tweak it
18162306a36Sopenharmony_ci *  when it's found to be wrong.
18262306a36Sopenharmony_ci *
18362306a36Sopenharmony_ci *  Known BIOS problems we have to work around:
18462306a36Sopenharmony_ci *	- I/O or memory regions not configured
18562306a36Sopenharmony_ci *	- regions configured, but not enabled in the command register
18662306a36Sopenharmony_ci *	- bogus I/O addresses above 64K used
18762306a36Sopenharmony_ci *	- expansion ROMs left enabled (this may sound harmless, but given
18862306a36Sopenharmony_ci *	  the fact the PCI specs explicitly allow address decoders to be
18962306a36Sopenharmony_ci *	  shared between expansion ROMs and other resource regions, it's
19062306a36Sopenharmony_ci *	  at least dangerous)
19162306a36Sopenharmony_ci *	- bad resource sizes or overlaps with other regions
19262306a36Sopenharmony_ci *
19362306a36Sopenharmony_ci *  Our solution:
19462306a36Sopenharmony_ci *	(1) Allocate resources for all buses behind PCI-to-PCI bridges.
19562306a36Sopenharmony_ci *	    This gives us fixed barriers on where we can allocate.
19662306a36Sopenharmony_ci *	(2) Allocate resources for all enabled devices.  If there is
19762306a36Sopenharmony_ci *	    a collision, just mark the resource as unallocated. Also
19862306a36Sopenharmony_ci *	    disable expansion ROMs during this step.
19962306a36Sopenharmony_ci *	(3) Try to allocate resources for disabled devices.  If the
20062306a36Sopenharmony_ci *	    resources were assigned correctly, everything goes well,
20162306a36Sopenharmony_ci *	    if they weren't, they won't disturb allocation of other
20262306a36Sopenharmony_ci *	    resources.
20362306a36Sopenharmony_ci *	(4) Assign new addresses to resources which were either
20462306a36Sopenharmony_ci *	    not configured at all or misconfigured.  If explicitly
20562306a36Sopenharmony_ci *	    requested by the user, configure expansion ROM address
20662306a36Sopenharmony_ci *	    as well.
20762306a36Sopenharmony_ci */
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_cistatic void pcibios_allocate_bridge_resources(struct pci_dev *dev)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	int idx;
21262306a36Sopenharmony_ci	struct resource *r;
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	for (idx = PCI_BRIDGE_RESOURCES; idx < PCI_NUM_RESOURCES; idx++) {
21562306a36Sopenharmony_ci		r = &dev->resource[idx];
21662306a36Sopenharmony_ci		if (!r->flags)
21762306a36Sopenharmony_ci			continue;
21862306a36Sopenharmony_ci		if (r->parent)	/* Already allocated */
21962306a36Sopenharmony_ci			continue;
22062306a36Sopenharmony_ci		if (!r->start || pci_claim_bridge_resource(dev, idx) < 0) {
22162306a36Sopenharmony_ci			/*
22262306a36Sopenharmony_ci			 * Something is wrong with the region.
22362306a36Sopenharmony_ci			 * Invalidate the resource to prevent
22462306a36Sopenharmony_ci			 * child resource allocations in this
22562306a36Sopenharmony_ci			 * range.
22662306a36Sopenharmony_ci			 */
22762306a36Sopenharmony_ci			r->start = r->end = 0;
22862306a36Sopenharmony_ci			r->flags = 0;
22962306a36Sopenharmony_ci		}
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_cistatic void pcibios_allocate_bus_resources(struct pci_bus *bus)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	struct pci_bus *child;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	/* Depth-First Search on bus tree */
23862306a36Sopenharmony_ci	if (bus->self)
23962306a36Sopenharmony_ci		pcibios_allocate_bridge_resources(bus->self);
24062306a36Sopenharmony_ci	list_for_each_entry(child, &bus->children, node)
24162306a36Sopenharmony_ci		pcibios_allocate_bus_resources(child);
24262306a36Sopenharmony_ci}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_cistruct pci_check_idx_range {
24562306a36Sopenharmony_ci	int start;
24662306a36Sopenharmony_ci	int end;
24762306a36Sopenharmony_ci};
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_cistatic void pcibios_allocate_dev_resources(struct pci_dev *dev, int pass)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	int idx, disabled, i;
25262306a36Sopenharmony_ci	u16 command;
25362306a36Sopenharmony_ci	struct resource *r;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	struct pci_check_idx_range idx_range[] = {
25662306a36Sopenharmony_ci		{ PCI_STD_RESOURCES, PCI_STD_RESOURCE_END },
25762306a36Sopenharmony_ci#ifdef CONFIG_PCI_IOV
25862306a36Sopenharmony_ci		{ PCI_IOV_RESOURCES, PCI_IOV_RESOURCE_END },
25962306a36Sopenharmony_ci#endif
26062306a36Sopenharmony_ci	};
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	pci_read_config_word(dev, PCI_COMMAND, &command);
26362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(idx_range); i++)
26462306a36Sopenharmony_ci		for (idx = idx_range[i].start; idx <= idx_range[i].end; idx++) {
26562306a36Sopenharmony_ci			r = &dev->resource[idx];
26662306a36Sopenharmony_ci			if (r->parent)	/* Already allocated */
26762306a36Sopenharmony_ci				continue;
26862306a36Sopenharmony_ci			if (!r->start)	/* Address not assigned at all */
26962306a36Sopenharmony_ci				continue;
27062306a36Sopenharmony_ci			if (r->flags & IORESOURCE_IO)
27162306a36Sopenharmony_ci				disabled = !(command & PCI_COMMAND_IO);
27262306a36Sopenharmony_ci			else
27362306a36Sopenharmony_ci				disabled = !(command & PCI_COMMAND_MEMORY);
27462306a36Sopenharmony_ci			if (pass == disabled) {
27562306a36Sopenharmony_ci				dev_dbg(&dev->dev,
27662306a36Sopenharmony_ci					"BAR %d: reserving %pr (d=%d, p=%d)\n",
27762306a36Sopenharmony_ci					idx, r, disabled, pass);
27862306a36Sopenharmony_ci				if (pci_claim_resource(dev, idx) < 0) {
27962306a36Sopenharmony_ci					if (r->flags & IORESOURCE_PCI_FIXED) {
28062306a36Sopenharmony_ci						dev_info(&dev->dev, "BAR %d %pR is immovable\n",
28162306a36Sopenharmony_ci							 idx, r);
28262306a36Sopenharmony_ci					} else {
28362306a36Sopenharmony_ci						/* We'll assign a new address later */
28462306a36Sopenharmony_ci						pcibios_save_fw_addr(dev,
28562306a36Sopenharmony_ci								idx, r->start);
28662306a36Sopenharmony_ci						r->end -= r->start;
28762306a36Sopenharmony_ci						r->start = 0;
28862306a36Sopenharmony_ci					}
28962306a36Sopenharmony_ci				}
29062306a36Sopenharmony_ci			}
29162306a36Sopenharmony_ci		}
29262306a36Sopenharmony_ci	if (!pass) {
29362306a36Sopenharmony_ci		r = &dev->resource[PCI_ROM_RESOURCE];
29462306a36Sopenharmony_ci		if (r->flags & IORESOURCE_ROM_ENABLE) {
29562306a36Sopenharmony_ci			/* Turn the ROM off, leave the resource region,
29662306a36Sopenharmony_ci			 * but keep it unregistered. */
29762306a36Sopenharmony_ci			u32 reg;
29862306a36Sopenharmony_ci			dev_dbg(&dev->dev, "disabling ROM %pR\n", r);
29962306a36Sopenharmony_ci			r->flags &= ~IORESOURCE_ROM_ENABLE;
30062306a36Sopenharmony_ci			pci_read_config_dword(dev, dev->rom_base_reg, &reg);
30162306a36Sopenharmony_ci			pci_write_config_dword(dev, dev->rom_base_reg,
30262306a36Sopenharmony_ci						reg & ~PCI_ROM_ADDRESS_ENABLE);
30362306a36Sopenharmony_ci		}
30462306a36Sopenharmony_ci	}
30562306a36Sopenharmony_ci}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_cistatic void pcibios_allocate_resources(struct pci_bus *bus, int pass)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	struct pci_dev *dev;
31062306a36Sopenharmony_ci	struct pci_bus *child;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	list_for_each_entry(dev, &bus->devices, bus_list) {
31362306a36Sopenharmony_ci		pcibios_allocate_dev_resources(dev, pass);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci		child = dev->subordinate;
31662306a36Sopenharmony_ci		if (child)
31762306a36Sopenharmony_ci			pcibios_allocate_resources(child, pass);
31862306a36Sopenharmony_ci	}
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_cistatic void pcibios_allocate_dev_rom_resource(struct pci_dev *dev)
32262306a36Sopenharmony_ci{
32362306a36Sopenharmony_ci	struct resource *r;
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci	/*
32662306a36Sopenharmony_ci	 * Try to use BIOS settings for ROMs, otherwise let
32762306a36Sopenharmony_ci	 * pci_assign_unassigned_resources() allocate the new
32862306a36Sopenharmony_ci	 * addresses.
32962306a36Sopenharmony_ci	 */
33062306a36Sopenharmony_ci	r = &dev->resource[PCI_ROM_RESOURCE];
33162306a36Sopenharmony_ci	if (!r->flags || !r->start)
33262306a36Sopenharmony_ci		return;
33362306a36Sopenharmony_ci	if (r->parent) /* Already allocated */
33462306a36Sopenharmony_ci		return;
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	if (pci_claim_resource(dev, PCI_ROM_RESOURCE) < 0) {
33762306a36Sopenharmony_ci		r->end -= r->start;
33862306a36Sopenharmony_ci		r->start = 0;
33962306a36Sopenharmony_ci	}
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_cistatic void pcibios_allocate_rom_resources(struct pci_bus *bus)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	struct pci_dev *dev;
34462306a36Sopenharmony_ci	struct pci_bus *child;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	list_for_each_entry(dev, &bus->devices, bus_list) {
34762306a36Sopenharmony_ci		pcibios_allocate_dev_rom_resource(dev);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci		child = dev->subordinate;
35062306a36Sopenharmony_ci		if (child)
35162306a36Sopenharmony_ci			pcibios_allocate_rom_resources(child);
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_cistatic int __init pcibios_assign_resources(void)
35662306a36Sopenharmony_ci{
35762306a36Sopenharmony_ci	struct pci_bus *bus;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if (!(pci_probe & PCI_ASSIGN_ROMS))
36062306a36Sopenharmony_ci		list_for_each_entry(bus, &pci_root_buses, node)
36162306a36Sopenharmony_ci			pcibios_allocate_rom_resources(bus);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	pci_assign_unassigned_resources();
36462306a36Sopenharmony_ci	pcibios_fw_addr_list_del();
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	return 0;
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci/*
37062306a36Sopenharmony_ci * This is an fs_initcall (one below subsys_initcall) in order to reserve
37162306a36Sopenharmony_ci * resources properly.
37262306a36Sopenharmony_ci */
37362306a36Sopenharmony_cifs_initcall(pcibios_assign_resources);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_civoid pcibios_resource_survey_bus(struct pci_bus *bus)
37662306a36Sopenharmony_ci{
37762306a36Sopenharmony_ci	dev_printk(KERN_DEBUG, &bus->dev, "Allocating resources\n");
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	pcibios_allocate_bus_resources(bus);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	pcibios_allocate_resources(bus, 0);
38262306a36Sopenharmony_ci	pcibios_allocate_resources(bus, 1);
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_ci	if (!(pci_probe & PCI_ASSIGN_ROMS))
38562306a36Sopenharmony_ci		pcibios_allocate_rom_resources(bus);
38662306a36Sopenharmony_ci}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_civoid __init pcibios_resource_survey(void)
38962306a36Sopenharmony_ci{
39062306a36Sopenharmony_ci	struct pci_bus *bus;
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	DBG("PCI: Allocating resources\n");
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	list_for_each_entry(bus, &pci_root_buses, node)
39562306a36Sopenharmony_ci		pcibios_allocate_bus_resources(bus);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	list_for_each_entry(bus, &pci_root_buses, node)
39862306a36Sopenharmony_ci		pcibios_allocate_resources(bus, 0);
39962306a36Sopenharmony_ci	list_for_each_entry(bus, &pci_root_buses, node)
40062306a36Sopenharmony_ci		pcibios_allocate_resources(bus, 1);
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	e820__reserve_resources_late();
40362306a36Sopenharmony_ci	/*
40462306a36Sopenharmony_ci	 * Insert the IO APIC resources after PCI initialization has
40562306a36Sopenharmony_ci	 * occurred to handle IO APICS that are mapped in on a BAR in
40662306a36Sopenharmony_ci	 * PCI space, but before trying to assign unassigned pci res.
40762306a36Sopenharmony_ci	 */
40862306a36Sopenharmony_ci	ioapic_insert_resources();
40962306a36Sopenharmony_ci}
410