• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
write_ssdt_domain_io_producer_range_helper(const char * domain_name,resource_t base,resource_t limit)11 static void write_ssdt_domain_io_producer_range_helper(const char *domain_name,
12 						       resource_t base, resource_t limit)
13 {
14 	printk(BIOS_DEBUG, "%s _CRS: adding IO range [%04llx-%04llx]\n", domain_name, base, limit);
15 	acpigen_resource_producer_io(base, limit);
16 }
17 
write_ssdt_domain_io_producer_range(const char * domain_name,resource_t base,resource_t limit)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 
write_ssdt_domain_mmio_producer_range(const char * domain_name,resource_t base,resource_t limit)38 static void write_ssdt_domain_mmio_producer_range(const char *domain_name,
39 						  resource_t base, resource_t limit)
40 {
41 	printk(BIOS_DEBUG, "%s _CRS: adding MMIO range [%016llx-%016llx]\n",
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 
pci_domain_fill_ssdt(const struct device * domain)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 */
57 	printk(BIOS_DEBUG, "%s _CRS: adding busses [%02x-%02x] in segment group %x\n",
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 }
107