soc/intel/common/systemagent_server: Add server platform system agent

Intel server processors have a different system agent design, it has
some differences with client platform such as (1) no BDSM and BGSM
registers; (2) different alignment size and bit fields in TOLUD,
TOUUD and TSEG registers. Thus this patch adds a new common block for
server platform system agent.

Change-Id: If32c2a6524c9d55ce7f9c3dd203bcf85cab76c2c
Signed-off-by: Yuchi Chen <yuchi.chen@intel.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/83318
Reviewed-by: Shuo Liu <shuo.liu@intel.com>
Reviewed-by: Angel Pons <th3fanbus@gmail.com>
Reviewed-by: Lean Sheng Tan <sheng.tan@9elements.com>
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
This commit is contained in:
Yuchi Chen 2024-10-12 16:53:59 +08:00 committed by Lean Sheng Tan
commit 239f7f7408
7 changed files with 417 additions and 0 deletions

View file

@ -0,0 +1,76 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#ifndef SOC_INTEL_COMMON_BLOCK_SA_SERVER_H
#define SOC_INTEL_COMMON_BLOCK_SA_SERVER_H
#include <device/device.h>
#include <device/pci_type.h>
#include <stdbool.h>
#include <stdint.h>
enum sa_server_reg {
MMCFG_BASE_REG,
MMCFG_LIMIT_REG,
TSEG_BASE_REG,
TSEG_LIMIT_REG,
TOCM_REG,
TOUUD_REG,
TOLUD_REG,
MMIO_L_REG,
VT_BAR_REG,
DPR_REG,
NUM_MAP_ENTRIES, /* Must be last. */
};
/**
* SoC implementation to convert register index to SoC-specific register PCIe configuration
* space offset.
*/
uint32_t sa_server_soc_reg_to_pci_offset(enum sa_server_reg reg);
struct sa_server_mem_map_descriptor {
uint32_t reg_offset; /* PCI configuration space offset. */
bool is_64_bit; /* If register is 64 bit. */
bool is_limit; /* If lower bits should be treated as 1s or 0s but always read as 0s. */
uint32_t alignment; /* Alignment of the address in register. Probing as PCI BAR if 0. */
};
uint64_t sa_server_read_map_entry(pci_devfn_t dev,
const struct sa_server_mem_map_descriptor *entry);
struct sa_server_mmio_descriptor {
uint64_t base;
uint64_t size;
bool (*get_resource)(struct device *dev, uint64_t *base, uint64_t *size);
const char *description; /* Name of the register. */
};
uintptr_t sa_server_get_tseg_base(void);
size_t sa_server_get_tseg_size(void);
uint64_t sa_server_get_touud(void);
uintptr_t sa_server_get_tolud(void);
/*
* API to determine whether system agent is on PCH domain or accelerators domains.
*/
bool sa_server_is_on_pch_domain(const struct device *dev);
/*
* API to add MMIO resources based on `struct sa_mmio_descriptor` provided by SoC.
*/
void sa_server_add_mmio_resources(
struct device *dev, int *resource_cnt,
const struct sa_server_mmio_descriptor *sa_server_fixed_resources, size_t count);
/**
* SoC call to provide all known fixed memory ranges for system agent.
*
* SoC function should provide fixed resource ranges in form of
* `struct sa_server_mmio_descriptor` along with resource count.
*/
void sa_server_soc_add_fixed_mmio_resources(struct device *dev, int *resource_cnt);
#endif // SOC_INTEL_COMMON_BLOCK_SA_SERVER_H

View file

@ -0,0 +1,24 @@
## SPDX-License-Identifier: GPL-2.0-only
config SOC_INTEL_COMMON_BLOCK_SA_SERVER
bool
help
Intel Server Processor common System Agent support
if SOC_INTEL_COMMON_BLOCK_SA_SERVER
config TOUUD_LIMIT
bool
default y
help
Specify if the lower bits in top of upper usable DRAM register should be
treated as 1s.
config TOLUD_LIMIT
bool
default y
help
Specify if the lower bits in top of lower usable DRAM register should be
treated as 1s.
endif

View file

@ -0,0 +1,9 @@
## SPDX-License-Identifier: GPL-2.0-only
romstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SA_SERVER) += common.c
romstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SA_SERVER) += memmap.c
romstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SA_SERVER) += systemagent_early.c
ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SA_SERVER) += common.c
ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SA_SERVER) += memmap.c
ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SA_SERVER) += systemagent.c
ramstage-$(CONFIG_SOC_INTEL_COMMON_BLOCK_SA_SERVER) += systemagent_early.c

View file

@ -0,0 +1,55 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#define __SIMPLE_DEVICE__
#include <device/pci_ops.h>
#include <intelblocks/systemagent_server.h>
static uint32_t pci_moving_config32(pci_devfn_t dev, unsigned int reg)
{
uint32_t value, ones, zeroes;
value = pci_read_config32(dev, reg);
pci_write_config32(dev, reg, 0xffffffff);
ones = pci_read_config32(dev, reg);
pci_write_config32(dev, reg, 0x00000000);
zeroes = pci_read_config32(dev, reg);
pci_write_config32(dev, reg, value);
return ones ^ zeroes;
}
uint64_t sa_server_read_map_entry(pci_devfn_t dev,
const struct sa_server_mem_map_descriptor *entry)
{
uint64_t value = 0;
uint32_t alignment = entry->alignment;
if (entry->is_64_bit) {
value = pci_s_read_config32(dev, entry->reg_offset + 4);
value <<= 32;
}
value |= pci_s_read_config32(dev, entry->reg_offset);
/**
* Probe the alignment if not provided, promising the lower bits are read only, otherwise
* SoC should give a initial value.
*/
if (!alignment)
alignment = ~pci_moving_config32(dev, entry->reg_offset) + 1;
/**
* If register stores the limit address, where lower bits are read as 0s but treated as 1s,
* restore the lower bits and align it up.
*/
if (entry->is_limit)
value = ALIGN_UP(value + alignment - 1, alignment);
else
value = ALIGN_DOWN(value, alignment);
return value;
}

View file

@ -0,0 +1,27 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <arch/romstage.h>
#include <console/console.h>
#include <cpu/x86/smm.h>
#include <intelblocks/systemagent_server.h>
void smm_region(uintptr_t *start, size_t *size)
{
*start = sa_server_get_tseg_base();
*size = sa_server_get_tseg_size();
}
void fill_postcar_frame(struct postcar_frame *pcf)
{
/*
* `postcar_mtrr_setup()` will be skipped if using FSP to tear down CAR.
*/
if (!CONFIG(NO_FSP_TEMP_RAM_EXIT))
return;
/*
* Add MTRR for ramstage, TSEG and extended BIOS region if exiting CAR without FSP is supporated.
*/
_Static_assert(!CONFIG(NO_FSP_TEMP_RAM_EXIT),
"NO_FSP_TEMP_RAM_EXIT is not supportted currently!");
}

View file

@ -0,0 +1,197 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#include <arch/vga.h>
#include <commonlib/bsd/helpers.h>
#include <device/pci.h>
#include <device/pci_ids.h>
#include <device/pci_type.h>
#include <fsp/util.h>
#include <intelblocks/acpi.h>
#include <intelblocks/systemagent_server.h>
#include <security/intel/txt/txt_register.h>
#include <soc/pci_devs.h>
#include <soc/systemagent.h>
__weak void sa_server_soc_add_fixed_mmio_resources(struct device *dev, int *resource_cnt)
{
}
__weak unsigned long sa_write_acpi_tables(const struct device *dev, unsigned long current,
struct acpi_rsdp *rsdp)
{
return current;
}
uint64_t sa_server_get_touud(void)
{
struct sa_server_mem_map_descriptor touud_descriptor = {
.reg_offset = sa_server_soc_reg_to_pci_offset(TOUUD_REG),
.is_64_bit = true,
.is_limit = CONFIG(TOUUD_LIMIT),
};
return sa_server_read_map_entry(PCI_BDF(SA_DEV_ROOT), &touud_descriptor);
}
uintptr_t sa_server_get_tolud(void)
{
struct sa_server_mem_map_descriptor tolud_descriptor = {
.reg_offset = sa_server_soc_reg_to_pci_offset(TOLUD_REG),
.is_limit = CONFIG(TOLUD_LIMIT),
};
return sa_server_read_map_entry(PCI_BDF(SA_DEV_ROOT), &tolud_descriptor);
}
bool sa_server_is_on_pch_domain(const struct device *dev)
{
return is_dev_on_domain0(dev);
}
void sa_server_add_mmio_resources(struct device *dev, int *resource_cnt,
const struct sa_server_mmio_descriptor *mmio_descriptors,
size_t count)
{
int index = *resource_cnt;
uint64_t base, size;
for (int i = 0; i < count; i++) {
base = mmio_descriptors[i].base;
size = mmio_descriptors[i].size;
/**
* Prefer to using `base` and `size` to retrieving them from `get_resource()` since
* some MMIO resources may not stored in any registers and registers may hold an
* incorrect value.
*/
if (!size)
if (!mmio_descriptors[i].get_resource ||
!mmio_descriptors[i].get_resource(dev, &base, &size))
continue;
printk(BIOS_DEBUG,
"SA MMIO resource: %-8s -> base = 0x%08llx, size = 0x%08llx\n",
mmio_descriptors[i].description, base, size);
mmio_range(dev, index++, base, size);
}
*resource_cnt = index;
}
/*
* Host Memory Map:
* +--------------------------+
* | MMIOH |
* | (relocatable) |
* +--------------------------+ TOUUD
* | High DRAM |
* +--------------------------+ 4GB (0x1_0000_0000)
* | Firmware |
* +--------------------------+ 0xFF00_0000
* | Reserved |
* +--------------------------+ 0xFEF0_0000
* | Local xAPIC |
* +--------------------------+ 0xFEE0_0000
* | HPET, Intel TXT, TPM |
* +--------------------------+ 0xFED0_0000
* | I/O xAPIC |
* +--------------------------+ 0xFEC0_0000
* | Reserved |
* +--------------------------+ MMIOL
* | MMIOL |
* | (relocatable) |
* +--------------------------+
* | PCIe MMCFG |
* | (relocatable) |
* +--------------------------+ TOLUD
* | MESEG (relocatable) |
* +--------------------------+
* | TSEG (relocatable) |
* +--------------------------+
* | DMA Protected Range |
* | (relocatable) |
* +--------------------------+ DPR base, 1M aligned
* | Unused memory (possible) |
* +--------------------------+ cbmem_top
* | FSP Bootloader TOLUM |
* +--------------------------+
* | FSP Reserved |
* +--------------------------+ top_of_ram
* | Low DRAM |
* | Legacy ISA hole |
* +--------------------------+ 0x10_0000 (1MB)
* | C, D, E, F segments |
* +--------------------------+ 0xC_0000
* | VGA (TSEG, MESEG) |
* +--------------------------+ 0xA_0000
* | DOS Range |
* +--------------------------+ 0
*/
static void sa_server_add_dram_resources(struct device *dev, int *resource_cnt)
{
int index = *resource_cnt;
/* 0 - > 0xa0000 */
ram_from_to(dev, index++, 0, 0xa0000);
/* 0xa0000 - > 0xc0000 */
mmio_range(dev, index++, VGA_MMIO_BASE, VGA_MMIO_SIZE);
/* 0xc0000 - > 1MB */
reserved_ram_from_to(dev, index++, 0xc0000, 1 * MiB);
/* 1MB -> top_of_ram (FSP reserved base) */
struct range_entry fsp_mem;
fsp_find_reserved_memory(&fsp_mem);
uint32_t top_of_ram = range_entry_base(&fsp_mem);
ram_from_to(dev, index++, 1 * MiB, top_of_ram);
/* top_of_ram -> cbmem_top, including FSP reserved and bootloader TOLUM. */
ram_from_to(dev, index++, top_of_ram, cbmem_top());
/* Mark cbmem_top to TOLUD as reserved, SoC should provide more details for this ranges. */
reserved_ram_from_to(dev, index++, cbmem_top(), sa_server_get_tolud());
/* 4GB -> TOUUD */
upper_ram_end(dev, index++, sa_server_get_touud());
*resource_cnt = index;
}
static void sa_server_read_resources(struct device *dev)
{
int index = 0;
pci_dev_read_resources(dev);
/*
* Only add DRAM resource when calling from PCH domain.
*/
if (sa_server_is_on_pch_domain(dev))
sa_server_add_dram_resources(dev, &index);
/* Add all SoC fixed MMIO resources. */
sa_server_soc_add_fixed_mmio_resources(dev, &index);
}
struct device_operations systemagent_server_ops = {
.read_resources = sa_server_read_resources,
.set_resources = pci_dev_set_resources,
.enable_resources = pci_dev_enable_resources,
.ops_pci = &pci_dev_ops_pci,
#if CONFIG(HAVE_ACPI_TABLES)
.write_acpi_tables = sa_write_acpi_tables,
#endif
};
static const unsigned short systemagent_server_ids[] = {
PCI_DID_INTEL_SNR_ID,
0
};
static const struct pci_driver systemagent_server_driver __pci_driver = {
.ops = &systemagent_server_ops,
.vendor = PCI_VID_INTEL,
.devices = systemagent_server_ids
};

View file

@ -0,0 +1,29 @@
/* SPDX-License-Identifier: GPL-2.0-only */
#define __SIMPLE_DEVICE__
#include <commonlib/bsd/helpers.h>
#include <device/pci_ops.h>
#include <intelblocks/systemagent_server.h>
#include <soc/pci_devs.h>
#include <soc/systemagent.h>
uintptr_t sa_server_get_tseg_base(void)
{
struct sa_server_mem_map_descriptor tseg_descriptor = {
.reg_offset = sa_server_soc_reg_to_pci_offset(TSEG_BASE_REG),
};
return sa_server_read_map_entry(SA_DEV_ROOT, &tseg_descriptor);
}
size_t sa_server_get_tseg_size(void)
{
struct sa_server_mem_map_descriptor tseg_descriptor = {
.reg_offset = sa_server_soc_reg_to_pci_offset(TSEG_LIMIT_REG),
.is_limit = true,
};
return sa_server_read_map_entry(SA_DEV_ROOT, &tseg_descriptor) -
sa_server_get_tseg_base();
}