162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/init.h>
362306a36Sopenharmony_ci#include <linux/pci.h>
462306a36Sopenharmony_ci#include <linux/range.h>
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include "bus_numa.h"
762306a36Sopenharmony_ci
862306a36Sopenharmony_ciLIST_HEAD(pci_root_infos);
962306a36Sopenharmony_ci
1062306a36Sopenharmony_cistatic struct pci_root_info *x86_find_pci_root_info(int bus)
1162306a36Sopenharmony_ci{
1262306a36Sopenharmony_ci	struct pci_root_info *info;
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci	list_for_each_entry(info, &pci_root_infos, list)
1562306a36Sopenharmony_ci		if (info->busn.start == bus)
1662306a36Sopenharmony_ci			return info;
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci	return NULL;
1962306a36Sopenharmony_ci}
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ciint x86_pci_root_bus_node(int bus)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	struct pci_root_info *info = x86_find_pci_root_info(bus);
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	if (!info)
2662306a36Sopenharmony_ci		return NUMA_NO_NODE;
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	return info->node;
2962306a36Sopenharmony_ci}
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_civoid x86_pci_root_bus_resources(int bus, struct list_head *resources)
3262306a36Sopenharmony_ci{
3362306a36Sopenharmony_ci	struct pci_root_info *info = x86_find_pci_root_info(bus);
3462306a36Sopenharmony_ci	struct pci_root_res *root_res;
3562306a36Sopenharmony_ci	struct resource_entry *window;
3662306a36Sopenharmony_ci	bool found = false;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	if (!info)
3962306a36Sopenharmony_ci		goto default_resources;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	printk(KERN_DEBUG "PCI: root bus %02x: hardware-probed resources\n",
4262306a36Sopenharmony_ci	       bus);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	/* already added by acpi ? */
4562306a36Sopenharmony_ci	resource_list_for_each_entry(window, resources)
4662306a36Sopenharmony_ci		if (window->res->flags & IORESOURCE_BUS) {
4762306a36Sopenharmony_ci			found = true;
4862306a36Sopenharmony_ci			break;
4962306a36Sopenharmony_ci		}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	if (!found)
5262306a36Sopenharmony_ci		pci_add_resource(resources, &info->busn);
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci	list_for_each_entry(root_res, &info->resources, list)
5562306a36Sopenharmony_ci		pci_add_resource(resources, &root_res->res);
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	return;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_cidefault_resources:
6062306a36Sopenharmony_ci	/*
6162306a36Sopenharmony_ci	 * We don't have any host bridge aperture information from the
6262306a36Sopenharmony_ci	 * "native host bridge drivers," e.g., amd_bus or broadcom_bus,
6362306a36Sopenharmony_ci	 * so fall back to the defaults historically used by pci_create_bus().
6462306a36Sopenharmony_ci	 */
6562306a36Sopenharmony_ci	printk(KERN_DEBUG "PCI: root bus %02x: using default resources\n", bus);
6662306a36Sopenharmony_ci	pci_add_resource(resources, &ioport_resource);
6762306a36Sopenharmony_ci	pci_add_resource(resources, &iomem_resource);
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistruct pci_root_info __init *alloc_pci_root_info(int bus_min, int bus_max,
7162306a36Sopenharmony_ci						 int node, int link)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	struct pci_root_info *info;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	info = kzalloc(sizeof(*info), GFP_KERNEL);
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	if (!info)
7862306a36Sopenharmony_ci		return info;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	sprintf(info->name, "PCI Bus #%02x", bus_min);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	INIT_LIST_HEAD(&info->resources);
8362306a36Sopenharmony_ci	info->busn.name  = info->name;
8462306a36Sopenharmony_ci	info->busn.start = bus_min;
8562306a36Sopenharmony_ci	info->busn.end   = bus_max;
8662306a36Sopenharmony_ci	info->busn.flags = IORESOURCE_BUS;
8762306a36Sopenharmony_ci	info->node = node;
8862306a36Sopenharmony_ci	info->link = link;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	list_add_tail(&info->list, &pci_root_infos);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	return info;
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_civoid update_res(struct pci_root_info *info, resource_size_t start,
9662306a36Sopenharmony_ci		resource_size_t end, unsigned long flags, int merge)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	struct resource *res;
9962306a36Sopenharmony_ci	struct pci_root_res *root_res;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	if (start > end)
10262306a36Sopenharmony_ci		return;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	if (start == RESOURCE_SIZE_MAX)
10562306a36Sopenharmony_ci		return;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	if (!merge)
10862306a36Sopenharmony_ci		goto addit;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	/* try to merge it with old one */
11162306a36Sopenharmony_ci	list_for_each_entry(root_res, &info->resources, list) {
11262306a36Sopenharmony_ci		resource_size_t final_start, final_end;
11362306a36Sopenharmony_ci		resource_size_t common_start, common_end;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci		res = &root_res->res;
11662306a36Sopenharmony_ci		if (res->flags != flags)
11762306a36Sopenharmony_ci			continue;
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci		common_start = max(res->start, start);
12062306a36Sopenharmony_ci		common_end = min(res->end, end);
12162306a36Sopenharmony_ci		if (common_start > common_end + 1)
12262306a36Sopenharmony_ci			continue;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci		final_start = min(res->start, start);
12562306a36Sopenharmony_ci		final_end = max(res->end, end);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci		res->start = final_start;
12862306a36Sopenharmony_ci		res->end = final_end;
12962306a36Sopenharmony_ci		return;
13062306a36Sopenharmony_ci	}
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ciaddit:
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	/* need to add that */
13562306a36Sopenharmony_ci	root_res = kzalloc(sizeof(*root_res), GFP_KERNEL);
13662306a36Sopenharmony_ci	if (!root_res)
13762306a36Sopenharmony_ci		return;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	res = &root_res->res;
14062306a36Sopenharmony_ci	res->name = info->name;
14162306a36Sopenharmony_ci	res->flags = flags;
14262306a36Sopenharmony_ci	res->start = start;
14362306a36Sopenharmony_ci	res->end = end;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	list_add_tail(&root_res->list, &info->resources);
14662306a36Sopenharmony_ci}
147