diff --git a/src/include/smbios.h b/src/include/smbios.h index f02b48b0c00..d5970fa17dd 100644 --- a/src/include/smbios.h +++ b/src/include/smbios.h @@ -270,6 +270,7 @@ typedef enum { SMBIOS_PORT_CONNECTOR_INFORMATION = 8, SMBIOS_SYSTEM_SLOTS = 9, SMBIOS_OEM_STRINGS = 11, + SMBIOS_GROUP_ASSOCIATIONS = 14, SMBIOS_EVENT_LOG = 15, SMBIOS_PHYS_MEMORY_ARRAY = 16, SMBIOS_MEMORY_DEVICE = 17, @@ -936,6 +937,14 @@ struct smbios_type11 { u8 eos[2]; } __packed; +struct smbios_type14 { + struct smbios_header header; + u8 group_name; + u8 item_type; + u16 item_handle; + u8 eos[2]; +} __packed; + struct smbios_type15 { struct smbios_header header; u16 area_length; diff --git a/src/mainboard/msi/ms7d25/mainboard.c b/src/mainboard/msi/ms7d25/mainboard.c index adb466519c9..b4c3b3d7ada 100644 --- a/src/mainboard/msi/ms7d25/mainboard.c +++ b/src/mainboard/msi/ms7d25/mainboard.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -505,6 +506,8 @@ static int mainboard_smbios_data(struct device *dev, int *handle, unsigned long { int len = 0; + len += cse_write_smbios_type14(handle, current); + // add port information len += smbios_write_type8( current, handle, diff --git a/src/mainboard/msi/ms7e06/mainboard.c b/src/mainboard/msi/ms7e06/mainboard.c index be30b6fbabf..7e322fa2695 100644 --- a/src/mainboard/msi/ms7e06/mainboard.c +++ b/src/mainboard/msi/ms7e06/mainboard.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -505,6 +506,8 @@ static int mainboard_smbios_data(struct device *dev, int *handle, unsigned long { int len = 0; + len += cse_write_smbios_type14(handle, current); + // add port information len += smbios_write_type8( current, handle, diff --git a/src/soc/intel/apollolake/Kconfig b/src/soc/intel/apollolake/Kconfig index bce935d8004..6a362126667 100644 --- a/src/soc/intel/apollolake/Kconfig +++ b/src/soc/intel/apollolake/Kconfig @@ -116,6 +116,10 @@ config MAX_HECI_DEVICES int default 3 +config MAX_MEI_DEVICES + int + default 3 + config MAX_CPUS int default 4 diff --git a/src/soc/intel/apollolake/heci.c b/src/soc/intel/apollolake/heci.c index 52dcca8de28..823e7d41b92 100644 --- a/src/soc/intel/apollolake/heci.c +++ b/src/soc/intel/apollolake/heci.c @@ -5,6 +5,7 @@ #include #include #include +#include uint32_t heci_fw_sts(void) { @@ -20,3 +21,17 @@ bool heci_cse_done(void) { return (!!(heci_fw_sts() & MASK_SEC_FIRMWARE_COMPLETE)); } + +unsigned int soc_get_heci_dev(unsigned int heci_idx) +{ + if (heci_idx > 2) + return 0; + + static const unsigned int heci_devs[] = { + PCH_DEVFN_CSE, + PCH_DEVFN_CSE_2, + PCH_DEVFN_CSE_3, + }; + + return heci_devs[heci_idx]; +} diff --git a/src/soc/intel/apollolake/include/soc/pci_devs.h b/src/soc/intel/apollolake/include/soc/pci_devs.h index cc31370d93f..0886f9aece9 100644 --- a/src/soc/intel/apollolake/include/soc/pci_devs.h +++ b/src/soc/intel/apollolake/include/soc/pci_devs.h @@ -62,7 +62,11 @@ #define PCH_DEV_SLOT_CSE 0x0f #define PCH_DEVFN_CSE _PCH_DEVFN(CSE, 0) +#define PCH_DEVFN_CSE_2 _PCH_DEVFN(CSE, 1) +#define PCH_DEVFN_CSE_3 _PCH_DEVFN(CSE, 2) #define PCH_DEV_CSE _PCH_DEV(CSE, 0) +#define PCH_DEV_CSE_2 _PCH_DEV(CSE, 1) +#define PCH_DEV_CSE_3 _PCH_DEV(CSE, 2) #define PCH_DEV_SLOT_ISH 0x11 #define PCH_DEVFN_ISH _PCH_DEVFN(ISH, 0) diff --git a/src/soc/intel/common/block/cse/Kconfig b/src/soc/intel/common/block/cse/Kconfig index f373bd9c8c8..378d9af1ad6 100644 --- a/src/soc/intel/common/block/cse/Kconfig +++ b/src/soc/intel/common/block/cse/Kconfig @@ -11,6 +11,10 @@ config MAX_HECI_DEVICES int default 6 +config MAX_MEI_DEVICES + int + default 4 + config SOC_INTEL_COMMON_BLOCK_CSE bool default n diff --git a/src/soc/intel/common/block/cse/cse.c b/src/soc/intel/common/block/cse/cse.c index 684619b61f5..2302859a431 100644 --- a/src/soc/intel/common/block/cse/cse.c +++ b/src/soc/intel/common/block/cse/cse.c @@ -76,6 +76,21 @@ #define MEI_HDR_CSE_ADDR_START 0 #define MEI_HDR_CSE_ADDR (((1 << 8) - 1) << MEI_HDR_CSE_ADDR_START) +__weak unsigned int soc_get_heci_dev(unsigned int heci_idx) +{ + if (heci_idx > 3) + return 0; + + const unsigned int heci_devs[] = { + PCI_DEVFN(0x16, 0), + PCI_DEVFN(0x16, 1), + PCI_DEVFN(0x16, 4), + PCI_DEVFN(0x16, 5) + }; + + return heci_devs[heci_idx]; +} + /* Get HECI BAR 0 from PCI configuration space */ static uintptr_t get_cse_bar(pci_devfn_t dev) { @@ -1577,6 +1592,96 @@ static void cse_final(struct device *dev) if (!CONFIG(USE_FSP_NOTIFY_PHASE_END_OF_FIRMWARE)) cse_final_end_of_firmware(); } +#if CONFIG(GENERATE_SMBIOS_TABLES) + +struct fwsts_record { + u8 heci_name; + u32 reg[6]; +} __packed; + +struct fwsts_smbios_table { + struct smbios_header header; + u8 version; + u8 count; + struct fwsts_record record[CONFIG_MAX_MEI_DEVICES]; + u8 eos[2]; +} __packed; + +static struct fwsts_record fwsts_cache[CONFIG_MAX_MEI_DEVICES] = { 0 }; + +static void fill_cse_fwsts(struct fwsts_record *rec, int idx) +{ + unsigned int heci_devfn = soc_get_heci_dev(idx); + pci_devfn_t heci; + + if (heci_devfn == 0) + return; + + heci = PCI_DEV(0, PCI_SLOT(heci_devfn), PCI_FUNC(heci_devfn)); + + if (pci_read_config16(heci, PCI_VENDOR_ID) != 0xffff && + pci_read_config16(heci, PCI_VENDOR_ID) != 0x0000) { + rec->reg[0] = pci_read_config32(heci, PCI_ME_HFSTS1); + rec->reg[1] = pci_read_config32(heci, PCI_ME_HFSTS2); + rec->reg[2] = pci_read_config32(heci, PCI_ME_HFSTS3); + rec->reg[3] = pci_read_config32(heci, PCI_ME_HFSTS4); + rec->reg[4] = pci_read_config32(heci, PCI_ME_HFSTS5); + rec->reg[5] = pci_read_config32(heci, PCI_ME_HFSTS6); + } else { + rec->reg[0] = 0xffffffff; + rec->reg[1] = 0xffffffff; + rec->reg[2] = 0xffffffff; + rec->reg[3] = 0xffffffff; + rec->reg[4] = 0xffffffff; + rec->reg[5] = 0xffffffff; + printk(BIOS_WARNING, "HECI: CSE device %02x.%01x is hidden\n", + PCI_SLOT(heci_devfn), PCI_FUNC(heci_devfn)); + } +} + +static void cache_cse_fwsts(void *unused) +{ + int i; + + for (i = 0; i < CONFIG_MAX_MEI_DEVICES; i++) + fill_cse_fwsts(&fwsts_cache[i], i); +} + +BOOT_STATE_INIT_ENTRY(BS_PRE_DEVICE, BS_ON_ENTRY, cache_cse_fwsts, NULL); + +int cse_write_smbios_type14(int *handle, unsigned long *current) +{ + int i, len; + char name[5]; + struct smbios_type14 *t = smbios_carve_table(*current, SMBIOS_GROUP_ASSOCIATIONS, + sizeof(*t), *handle); + + *handle += 1; + t->group_name = smbios_add_string(t->eos, "$MEI"); + t->item_type = 0xdb; + t->item_handle = *handle; + + len = smbios_full_table_len(&t->header, t->eos); + + struct fwsts_smbios_table *fwsts = smbios_carve_table(*current + len, 0xdb, + sizeof(*fwsts), *handle); + + *handle += 1; + fwsts->version = 1; + fwsts->count = CONFIG_MAX_MEI_DEVICES; + + for (i = 0; i < CONFIG_MAX_MEI_DEVICES; i++) { + snprintf(name, sizeof(name), "MEI%d", i + 1); + fwsts->record[i].heci_name = smbios_add_string(fwsts->eos, name); + memcpy(fwsts->record[i].reg, fwsts_cache[i].reg, sizeof(fwsts->record[i].reg)); + } + + len += smbios_full_table_len(&fwsts->header, fwsts->eos); + *current += len; + + return len; +} +#endif struct device_operations cse_ops = { .set_resources = pci_dev_set_resources, diff --git a/src/soc/intel/common/block/include/intelblocks/cse.h b/src/soc/intel/common/block/include/intelblocks/cse.h index ae9fe941c67..95298e189f5 100644 --- a/src/soc/intel/common/block/include/intelblocks/cse.h +++ b/src/soc/intel/common/block/include/intelblocks/cse.h @@ -572,4 +572,8 @@ void cse_enable_ptt(bool state); */ enum cb_err cse_get_fw_feature_state(uint32_t *feature_state); +unsigned int soc_get_heci_dev(unsigned int heci_idx); + +int cse_write_smbios_type14(int *handle, unsigned long *current); + #endif // SOC_INTEL_COMMON_CSE_H diff --git a/src/soc/intel/denverton_ns/Kconfig b/src/soc/intel/denverton_ns/Kconfig index 55ba2cdae91..4c8c5a8900d 100644 --- a/src/soc/intel/denverton_ns/Kconfig +++ b/src/soc/intel/denverton_ns/Kconfig @@ -74,6 +74,14 @@ config MAX_CPUS int default 16 +config MAX_HECI_DEVICES + int + default 5 + +config MAX_MEI_DEVICES + int + default 3 + config PCR_BASE_ADDRESS hex default 0xfd000000 diff --git a/src/soc/intel/denverton_ns/Makefile.inc b/src/soc/intel/denverton_ns/Makefile.inc index 5d9b32773bd..be0e2635d71 100644 --- a/src/soc/intel/denverton_ns/Makefile.inc +++ b/src/soc/intel/denverton_ns/Makefile.inc @@ -68,6 +68,8 @@ verstage-y += spi.c verstage-y += tsc_freq.c verstage-$(CONFIG_DRIVERS_UART_8250MEM) += uart_debug.c +all-y += me.c + CPPFLAGS_common += -I$(src)/soc/intel/denverton_ns/include cpu_microcode_bins += 3rdparty/intel-microcode/intel-ucode/06-5f-01 diff --git a/src/soc/intel/denverton_ns/me.c b/src/soc/intel/denverton_ns/me.c new file mode 100644 index 00000000000..c205b05a4a2 --- /dev/null +++ b/src/soc/intel/denverton_ns/me.c @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include +#include + +unsigned int soc_get_heci_dev(unsigned int heci_idx) +{ + if (heci_idx > 2) + return 0; + + static const unsigned int heci_devs[] = { + PCH_DEVFN_ME_HECI1, + PCH_DEVFN_ME_HECI2, + PCH_DEVFN_ME_HECI3, + }; + + return heci_devs[heci_idx]; +} diff --git a/src/soc/intel/skylake/Kconfig b/src/soc/intel/skylake/Kconfig index d6a11363ee2..244171aabd3 100644 --- a/src/soc/intel/skylake/Kconfig +++ b/src/soc/intel/skylake/Kconfig @@ -93,6 +93,10 @@ config MAX_HECI_DEVICES int default 5 +config MAX_MEI_DEVICES + int + default 3 + config MAX_CPUS int default 16 if MAINBOARD_SUPPORTS_COFFEELAKE_CPU diff --git a/src/soc/intel/skylake/me.c b/src/soc/intel/skylake/me.c index 89491f89c37..0699baa3621 100644 --- a/src/soc/intel/skylake/me.c +++ b/src/soc/intel/skylake/me.c @@ -181,6 +181,20 @@ static const char *const me_progress_bup_values[] = { "M0 kernel load", }; +unsigned int soc_get_heci_dev(unsigned int heci_idx) +{ + if (heci_idx > 2) + return 0; + + static const unsigned int heci_devs[] = { + PCH_DEVFN_CSE, + PCH_DEVFN_CSE_2, + PCH_DEVFN_CSE_3 + }; + + return heci_devs[heci_idx]; +} + void intel_me_status(void) { union me_hfsts1 hfs1;