/* SPDX-License-Identifier: GPL-2.0-only */

#include <cpu/x86/smm.h>
#include <device/device.h>
#include <device/pci_def.h>
#include <device/pci_ops.h>

void smm_pci_get_stored_resources(const volatile struct smm_pci_resource_info **out_slots,
				  size_t *out_size)
{
	*out_slots = smm_get_pci_resource_store();
	*out_size = CONFIG_SMM_PCI_RESOURCE_STORE_NUM_SLOTS;
}

bool smm_pci_resource_store_fill_resources(struct smm_pci_resource_info *slots, size_t num_slots,
					   const struct device **devices, size_t num_devices)
{
	size_t i_slot = 0;

	for (size_t i_dev = 0; i_dev < num_devices; i_dev++) {
		if (i_slot >= num_slots) {
			printk(BIOS_ERR, "Failed to store all PCI resources, number of devices exceeds %zd slots\n",
			       num_slots);
			return false;
		}

		if (!is_pci(devices[i_dev])) {
			printk(BIOS_WARNING, "Skipping storing PCI resources for device at index %zd, not a PCI device\n",
			       i_dev);
			continue;
		}

		pci_devfn_t pci_addr = PCI_BDF(devices[i_dev]);
		slots[i_slot].pci_addr = pci_addr;
		slots[i_slot].class_device = PCI_CLASS_GET_DEVICE(devices[i_dev]->class);
		slots[i_slot].class_prog = PCI_CLASS_GET_PROG(devices[i_dev]->class);
		slots[i_slot].vendor_id = devices[i_dev]->vendor;
		slots[i_slot].device_id = devices[i_dev]->device;

		size_t i_res = 0;
		for (const struct resource *res = devices[i_dev]->resource_list; res != NULL;
			res = res->next) {
			slots[i_slot].resources[i_res] = *res;
			slots[i_slot].resources[i_res].next = NULL;

			if (i_res > 0)
				slots[i_slot].resources[i_res - 1].next = (struct resource *)&slots[i_slot].resources[i_res];

			if (++i_res >= SMM_PCI_RESOURCE_STORE_NUM_RESOURCES) {
				if (res->next)
					printk(BIOS_WARNING, "Number of PCI resources exceeds supported storage count\n");
				break;
			}
		}

		i_slot++;
	}

	return true;
}

void __weak smm_mainboard_pci_resource_store_init(struct smm_pci_resource_info *slots,
						  size_t size)
{
}

void smm_pci_resource_store_init(struct smm_runtime *smm_runtime)
{
	smm_mainboard_pci_resource_store_init(&smm_runtime->pci_resources[0],
					 CONFIG_SMM_PCI_RESOURCE_STORE_NUM_SLOTS);
}
