Felix Held | e549ee0 | 2024-02-12 22:28:17 +0100 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
| 2 | |
| 3 | #include <acpi/acpigen.h> |
| 4 | #include <acpi/acpigen_pci.h> |
| 5 | #include <arch/pci_io_cfg.h> |
| 6 | #include <arch/vga.h> |
| 7 | #include <console/console.h> |
| 8 | #include <device/device.h> |
| 9 | #include <types.h> |
| 10 | |
| 11 | static void write_ssdt_domain_io_producer_range_helper(const char *domain_name, |
| 12 | resource_t base, resource_t limit) |
| 13 | { |
Felix Held | 0ada3da | 2024-02-29 16:45:12 +0100 | [diff] [blame] | 14 | printk(BIOS_DEBUG, "%s _CRS: adding IO range [%04llx-%04llx]\n", domain_name, base, limit); |
Felix Held | e549ee0 | 2024-02-12 22:28:17 +0100 | [diff] [blame] | 15 | acpigen_resource_producer_io(base, limit); |
| 16 | } |
| 17 | |
| 18 | static void write_ssdt_domain_io_producer_range(const char *domain_name, |
| 19 | resource_t base, resource_t limit) |
| 20 | { |
| 21 | /* |
| 22 | * Split the IO region at the PCI config IO ports so that the IO resource producer |
| 23 | * won't cover the same IO ports that the IO resource consumer for the PCI config IO |
| 24 | * ports in the same ACPI device already covers. |
| 25 | */ |
| 26 | if (base < PCI_IO_CONFIG_INDEX) { |
| 27 | write_ssdt_domain_io_producer_range_helper(domain_name, |
| 28 | base, |
| 29 | MIN(limit, PCI_IO_CONFIG_INDEX - 1)); |
| 30 | } |
| 31 | if (limit > PCI_IO_CONFIG_LAST_PORT) { |
| 32 | write_ssdt_domain_io_producer_range_helper(domain_name, |
| 33 | MAX(base, PCI_IO_CONFIG_LAST_PORT + 1), |
| 34 | limit); |
| 35 | } |
| 36 | } |
| 37 | |
| 38 | static void write_ssdt_domain_mmio_producer_range(const char *domain_name, |
| 39 | resource_t base, resource_t limit) |
| 40 | { |
Felix Held | 0ada3da | 2024-02-29 16:45:12 +0100 | [diff] [blame] | 41 | printk(BIOS_DEBUG, "%s _CRS: adding MMIO range [%016llx-%016llx]\n", |
Felix Held | e549ee0 | 2024-02-12 22:28:17 +0100 | [diff] [blame] | 42 | domain_name, base, limit); |
| 43 | acpigen_resource_producer_mmio(base, limit, |
| 44 | MEM_RSRC_FLAG_MEM_READ_WRITE | MEM_RSRC_FLAG_MEM_ATTR_NON_CACHE); |
| 45 | } |
| 46 | |
| 47 | void pci_domain_fill_ssdt(const struct device *domain) |
| 48 | { |
| 49 | const char *acpi_scope = acpi_device_path(domain); |
| 50 | printk(BIOS_DEBUG, "%s ACPI scope: '%s'\n", __func__, acpi_scope); |
| 51 | acpigen_write_scope(acpi_device_path(domain)); |
| 52 | |
| 53 | acpigen_write_name("_CRS"); |
| 54 | acpigen_write_resourcetemplate_header(); |
| 55 | |
| 56 | /* PCI bus number range in domain */ |
Felix Held | 0ada3da | 2024-02-29 16:45:12 +0100 | [diff] [blame] | 57 | printk(BIOS_DEBUG, "%s _CRS: adding busses [%02x-%02x] in segment group %x\n", |
Felix Held | e549ee0 | 2024-02-12 22:28:17 +0100 | [diff] [blame] | 58 | acpi_device_name(domain), domain->downstream->secondary, |
| 59 | domain->downstream->max_subordinate, domain->downstream->segment_group); |
| 60 | acpigen_resource_producer_bus_number(domain->downstream->secondary, |
| 61 | domain->downstream->max_subordinate); |
| 62 | |
| 63 | if (domain->path.domain.domain == 0) { |
| 64 | /* ACPI 6.4.2.5 I/O Port Descriptor */ |
| 65 | acpigen_write_io16(PCI_IO_CONFIG_INDEX, PCI_IO_CONFIG_LAST_PORT, 1, |
| 66 | PCI_IO_CONFIG_PORT_COUNT, 1); |
| 67 | } |
| 68 | |
| 69 | struct resource *res; |
| 70 | for (res = domain->resource_list; res != NULL; res = res->next) { |
| 71 | if (!(res->flags & IORESOURCE_ASSIGNED)) |
| 72 | continue; |
| 73 | /* Don't add MMIO producer ranges for reserved MMIO regions from non-PCI |
| 74 | devices */ |
| 75 | if (res->flags & IORESOURCE_RESERVE) |
| 76 | continue; |
| 77 | /* Don't add MMIO producer ranges for DRAM regions */ |
| 78 | if (res->flags & IORESOURCE_STORED) |
| 79 | continue; |
| 80 | switch (res->flags & IORESOURCE_TYPE_MASK) { |
| 81 | case IORESOURCE_IO: |
| 82 | write_ssdt_domain_io_producer_range(acpi_device_name(domain), |
| 83 | res->base, res->limit); |
| 84 | break; |
| 85 | case IORESOURCE_MEM: |
| 86 | write_ssdt_domain_mmio_producer_range(acpi_device_name(domain), |
| 87 | res->base, res->limit); |
| 88 | break; |
| 89 | default: |
| 90 | break; |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | if (domain->downstream->bridge_ctrl & PCI_BRIDGE_CTL_VGA) { |
| 95 | printk(BIOS_DEBUG, "%s _CRS: adding VGA resource\n", acpi_device_name(domain)); |
| 96 | acpigen_resource_producer_mmio(VGA_MMIO_BASE, VGA_MMIO_LIMIT, |
| 97 | MEM_RSRC_FLAG_MEM_READ_WRITE | MEM_RSRC_FLAG_MEM_ATTR_CACHE); |
| 98 | } |
| 99 | |
| 100 | acpigen_write_resourcetemplate_footer(); |
| 101 | |
| 102 | acpigen_write_SEG(domain->downstream->segment_group); |
| 103 | acpigen_write_BBN(domain->downstream->secondary); |
| 104 | /* Scope */ |
| 105 | acpigen_pop_len(); |
| 106 | } |