/* SPDX-License-Identifier: GPL-2.0-only */ #include #include #include #include #include #include #include #include /* * Used for IIO stacks for accelerators and other functionality (IOAT). * Those have only integrated PCI endpoints (no bridges) behind the host bridge. */ static struct device_operations ioat_domain_ops = { .read_resources = noop_read_resources, .set_resources = pci_domain_set_resources, .scan_bus = pci_host_bridge_scan_bus, }; static void create_ioat_domain(const union xeon_domain_path dp, struct bus *const upstream, const unsigned int bus_base, const unsigned int bus_limit, const resource_t mem32_base, const resource_t mem32_limit, const resource_t mem64_base, const resource_t mem64_limit) { union xeon_domain_path new_path = { .domain_path = dp.domain_path }; new_path.bus = bus_base; struct device_path path = { .type = DEVICE_PATH_DOMAIN, .domain = { .domain = new_path.domain_path, }, }; struct device *const domain = alloc_dev(upstream, &path); if (!domain) die("%s: out of memory.\n", __func__); domain->ops = &ioat_domain_ops; struct bus *const bus = alloc_bus(domain); bus->secondary = bus_base; bus->subordinate = bus->secondary; bus->max_subordinate = bus_limit; unsigned int index = 0; if (mem32_base <= mem32_limit) { struct resource *const res = new_resource(domain, index++); res->base = mem32_base; res->limit = mem32_limit; res->size = res->limit - res->base + 1; res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED; } if (mem64_base <= mem64_limit) { struct resource *const res = new_resource(domain, index++); res->base = mem64_base; res->limit = mem64_limit; res->size = res->limit - res->base + 1; res->flags = IORESOURCE_MEM | IORESOURCE_ASSIGNED; } } void soc_create_ioat_domains(const union xeon_domain_path path, struct bus *const bus, const STACK_RES *const sr) { if (sr->BusLimit < sr->BusBase + HQM_BUS_OFFSET + HQM_RESERVED_BUS) { printk(BIOS_WARNING, "Ignoring IOAT domain with limited bus range.\n"); return; } if (sr->PciResourceMem64Limit - sr->PciResourceMem64Base + 1 < 2 * CPM_MMIO_SIZE + 2 * HQM_MMIO_SIZE) { printk(BIOS_WARNING, "Ignoring IOAT domain with limited 64-bit MMIO window.\n"); return; } /* The FSP HOB doesn't provide accurate information about the resource allocation. Hence use pre-defined offsets. Based on ACPI code in create_dsdt_dino_resource(), soc_acpi.c: */ resource_t mem64_base, mem64_limit, bus_base, bus_limit; /* CPM0 */ mem64_base = sr->PciResourceMem64Base; mem64_limit = mem64_base + CPM_MMIO_SIZE - 1; bus_base = sr->BusBase + CPM_BUS_OFFSET; bus_limit = bus_base + CPM_RESERVED_BUS; create_ioat_domain(path, bus, bus_base, bus_limit, 0, -1, mem64_base, mem64_limit); /* HQM0 */ mem64_base = mem64_limit + 1; mem64_limit = mem64_base + HQM_MMIO_SIZE - 1; bus_base = sr->BusBase + HQM_BUS_OFFSET; bus_limit = bus_base + HQM_RESERVED_BUS; create_ioat_domain(path, bus, bus_base, bus_limit, 0, -1, mem64_base, mem64_limit); /* CPM1 (optional) */ mem64_base = mem64_limit + 1; mem64_limit = mem64_base + CPM_MMIO_SIZE - 1; bus_base = sr->BusBase + CPM1_BUS_OFFSET; bus_limit = bus_base + CPM_RESERVED_BUS; if (bus_limit <= sr->BusLimit) create_ioat_domain(path, bus, bus_base, bus_limit, 0, -1, mem64_base, mem64_limit); /* HQM1 (optional) */ mem64_base = mem64_limit + 1; mem64_limit = mem64_base + HQM_MMIO_SIZE - 1; bus_base = sr->BusBase + HQM1_BUS_OFFSET; bus_limit = bus_base + HQM_RESERVED_BUS; if (bus_limit <= sr->BusLimit) create_ioat_domain(path, bus, bus_base, bus_limit, 0, -1, mem64_base, mem64_limit); /* DINO */ mem64_base = mem64_limit + 1; mem64_limit = sr->PciResourceMem64Limit; bus_base = sr->BusBase; bus_limit = bus_base; create_ioat_domain(path, bus, bus_base, bus_limit, sr->PciResourceMem32Base, sr->PciResourceMem32Limit, mem64_base, mem64_limit); }