diff mbox series

[06/10] sysinfo: Add sysinfo driver for SMBIOS type 7

Message ID 20240816154658.1866186-7-raymond.mao@linaro.org
State Changes Requested
Delegated to: Tom Rini
Headers show
Series SMBIOS improvements | expand

Commit Message

Raymond Mao Aug. 16, 2024, 3:46 p.m. UTC
Add sysinfo interface and data structures for cache information
required by SMBIOS type 7.

Signed-off-by: Raymond Mao <raymond.mao@linaro.org>
---
 drivers/sysinfo/smbios_plat.c | 172 ++++++++++++++++++++++++++++++++++
 drivers/sysinfo/smbios_plat.h |  27 ++++++
 include/smbios.h              | 112 ++++++++++++++++++++++
 include/sysinfo.h             |  36 +++++++
 4 files changed, 347 insertions(+)
diff mbox series

Patch

diff --git a/drivers/sysinfo/smbios_plat.c b/drivers/sysinfo/smbios_plat.c
index adbc8cf3cf2..e225b42d672 100644
--- a/drivers/sysinfo/smbios_plat.c
+++ b/drivers/sysinfo/smbios_plat.c
@@ -12,14 +12,60 @@  struct sysinfo_plat_priv {
 	struct baseboard_info *t2;
 	struct enclosure_info *t3;
 	struct processor_info *t4;
+	struct smbios_type7 t7[SYSINFO_CACHE_LVL_MAX];
+	char *cache_socket_design[SYSINFO_CACHE_LVL_MAX];
+	u16 cache_handles[SYSINFO_CACHE_LVL_MAX];
+	u8 cache_level;
+	/*
+	 * TODO: add other types here:
+	 * Type 9 - System Slots
+	 * Type 16 - Physical Memory Array
+	 * Type 17 - Memory Device
+	 * Type 19 - Memory Array Mapped Address
+	 */
 };
 
+static void smbios_cache_info_dump(struct smbios_type7 *cache_info)
+{
+	log_debug("SMBIOS Type 7 (Cache Information):\n");
+	log_debug("Cache Configuration: 0x%04x\n", cache_info->config.data);
+	log_debug("Maximum Cache Size: %u KB\n", cache_info->max_size.data);
+	log_debug("Installed Size: %u KB\n", cache_info->inst_size.data);
+	log_debug("Supported SRAM Type: 0x%04x\n",
+		  cache_info->supp_sram_type.data);
+	log_debug("Current SRAM Type: 0x%04x\n",
+		  cache_info->curr_sram_type.data);
+	log_debug("Cache Speed: %u\n", cache_info->speed);
+	log_debug("Error Correction Type: %u\n", cache_info->err_corr_type);
+	log_debug("System Cache Type: %u\n", cache_info->sys_cache_type);
+	log_debug("Associativity: %u\n", cache_info->associativity);
+	log_debug("Maximum Cache Size 2: %u KB\n", cache_info->max_size2.data);
+	log_debug("Installed Cache Size 2: %u KB\n",
+		  cache_info->inst_size2.data);
+}
+
 /* weak function for the platforms not yet supported */
+__weak int sysinfo_get_cache_info(u8 level, struct cache_info *cache_info)
+{
+	return -ENOSYS;
+}
 __weak int sysinfo_get_processor_info(struct processor_info *pinfo)
 {
 	return -ENOSYS;
 }
 
+void sysinfo_cache_info_default(struct cache_info *ci)
+{
+	memset(ci, 0, sizeof(*ci));
+	ci->config.fields.locate = SMBIOS_CACHE_LOCATE_UNKNOWN;
+	ci->config.fields.opmode = SMBIOS_CACHE_OP_UND;
+	ci->supp_sram_type.fields.unknown = 1;
+	ci->curr_sram_type.fields.unknown = 1;
+	ci->speed = SMBIOS_CACHE_SPEED_UNKNOWN;
+	ci->err_corr_type = SMBIOS_CACHE_ERRCORR_UNKNOWN;
+	ci->cache_type = SMBIOS_CACHE_SYSCACHE_TYPE_UNKNOWN;
+}
+
 static int sysinfo_plat_detect(struct udevice *dev)
 {
 	return 0;
@@ -30,6 +76,22 @@  static int sysinfo_plat_get_str(struct udevice *dev, int id,
 {
 	struct sysinfo_plat_priv *priv = dev_get_priv(dev);
 	const char *str = NULL;
+	u8 i;
+
+	if (id >= SYSINFO_ID_SMBIOS_CACHE_INFO_START &&
+	    id <= SYSINFO_ID_SMBIOS_CACHE_INFO_END) {
+		/* For smbios type 7 */
+		for (i = 0; i < priv->cache_level; i++) {
+			switch (id - i) {
+			case SYSINFO_ID_SMBIOS_CACHE_SOCKET:
+				str = priv->cache_socket_design[i];
+				break;
+			default:
+				break;
+			}
+		}
+		goto handle_str;
+	}
 
 	switch (id) {
 	case SYSINFO_ID_SMBIOS_SYSTEM_MANUFACTURER:
@@ -105,6 +167,7 @@  static int sysinfo_plat_get_str(struct udevice *dev, int id,
 		break;
 	}
 
+handle_str:
 	if (!str)
 		return -ENOSYS;
 
@@ -116,6 +179,52 @@  static int sysinfo_plat_get_str(struct udevice *dev, int id,
 static int sysinfo_plat_get_int(struct udevice *dev, int id, int *val)
 {
 	struct sysinfo_plat_priv *priv = dev_get_priv(dev);
+	u8 i;
+
+	if (id >= SYSINFO_ID_SMBIOS_CACHE_INFO_START &&
+	    id <= SYSINFO_ID_SMBIOS_CACHE_INFO_END) {
+		/* For smbios type 7 */
+		for (i = 0; i < priv->cache_level; i++) {
+			switch (id - i) {
+			case SYSINFO_ID_SMBIOS_CACHE_CONFIG:
+				*val = priv->t7[i].config.data;
+				break;
+			case SYSINFO_ID_SMBIOS_CACHE_MAX_SIZE:
+				*val = priv->t7[i].max_size.data;
+				break;
+			case SYSINFO_ID_SMBIOS_CACHE_INST_SIZE:
+				*val = priv->t7[i].inst_size.data;
+				break;
+			case SYSINFO_ID_SMBIOS_CACHE_SUPSRAM_TYPE:
+				*val = priv->t7[i].supp_sram_type.data;
+				break;
+			case SYSINFO_ID_SMBIOS_CACHE_CURSRAM_TYPE:
+				*val = priv->t7[i].curr_sram_type.data;
+				break;
+			case SYSINFO_ID_SMBIOS_CACHE_SPEED:
+				*val = priv->t7[i].speed;
+				break;
+			case SYSINFO_ID_SMBIOS_CACHE_ERRCOR_TYPE:
+				*val = priv->t7[i].err_corr_type;
+				break;
+			case SYSINFO_ID_SMBIOS_CACHE_SCACHE_TYPE:
+				*val = priv->t7[i].sys_cache_type;
+				break;
+			case SYSINFO_ID_SMBIOS_CACHE_ASSOC:
+				*val = priv->t7[i].associativity;
+				break;
+			case SYSINFO_ID_SMBIOS_CACHE_MAX_SIZE2:
+				*val = priv->t7[i].max_size2.data;
+				break;
+			case SYSINFO_ID_SMBIOS_CACHE_INST_SIZE2:
+				*val = priv->t7[i].inst_size2.data;
+				break;
+			default:
+				break;
+			}
+		}
+		return 0;
+	}
 
 	switch (id) {
 	case SYSINFO_ID_SMBIOS_SYSTEM_WAKEUP:
@@ -208,6 +317,11 @@  static int sysinfo_plat_get_int(struct udevice *dev, int id, int *val)
 	case SYSINFO_ID_SMBIOS_PROCESSOR_THREAD_EN:
 		*val = priv->t4->thread_enabled;
 		break;
+	case SYSINFO_ID_SMBIOS_CACHE_LEVEL:
+		if (!priv->cache_level)	/* No cache detected */
+			return -ENOSYS;
+		*val = priv->cache_level - 1;
+		break;
 	default:
 		break;
 	}
@@ -233,6 +347,10 @@  static int sysinfo_plat_get_data(struct udevice *dev, int id, uchar **buf,
 		*buf = (uchar *)priv->t4->id;
 		*size = sizeof(priv->t4->id);
 		break;
+	case SYSINFO_ID_SMBIOS_CACHE_HANDLE:
+		*buf = (uchar *)(&priv->cache_handles[0]);
+		*size = sizeof(priv->cache_handles);
+		break;
 	default:
 		break;
 	}
@@ -243,6 +361,7 @@  static int sysinfo_plat_probe(struct udevice *dev)
 {
 	struct sysinfo_plat_priv *priv = dev_get_priv(dev);
 	struct sysinfo_plat *plat = dev_get_plat(dev);
+	u8 level;
 
 	priv->t1 = &plat->sys;
 	priv->t2 = &plat->board;
@@ -251,6 +370,59 @@  static int sysinfo_plat_probe(struct udevice *dev)
 	if (!sysinfo_get_processor_info(plat->processor))
 		priv->t4 = plat->processor;
 
+	for (level = 0; level < SYSINFO_CACHE_LVL_MAX; level++) {
+		struct cache_info *pcache = plat->cache + level;
+
+		if (sysinfo_get_cache_info(level, pcache))
+			break; /* no more levels */
+
+		/*
+		 * Fill in the SMBIOS type 7 structure,
+		 * skip the header members - type, length, handle
+		 */
+		priv->t7[level].config.data = pcache->config.data;
+		priv->t7[level].supp_sram_type.data =
+			pcache->supp_sram_type.data;
+		priv->t7[level].curr_sram_type.data =
+			pcache->curr_sram_type.data;
+		priv->t7[level].speed = pcache->speed;
+		priv->t7[level].err_corr_type = pcache->err_corr_type;
+		priv->t7[level].sys_cache_type = pcache->cache_type;
+		priv->t7[level].associativity = pcache->associativity;
+
+		if (pcache->max_size > SMBIOS_CACHE_SIZE_EXT_KB) {
+			priv->t7[level].max_size.data = 0xFFFF;
+			priv->t7[level].max_size2.fields.size =
+				pcache->max_size / 64;
+			priv->t7[level].max_size2.fields.granu =
+				SMBIOS_CACHE_GRANU_64K;
+		} else {
+			priv->t7[level].max_size.fields.size = pcache->max_size;
+			priv->t7[level].max_size.fields.granu =
+				SMBIOS_CACHE_GRANU_1K;
+			priv->t7[level].max_size2.data = 0;
+		}
+		if (pcache->inst_size > SMBIOS_CACHE_SIZE_EXT_KB) {
+			priv->t7[level].inst_size.data = 0xFFFF;
+			priv->t7[level].inst_size2.fields.size =
+				pcache->inst_size / 64;
+			priv->t7[level].inst_size2.fields.granu =
+				SMBIOS_CACHE_GRANU_64K;
+		} else {
+			priv->t7[level].inst_size.fields.size =
+				pcache->inst_size;
+			priv->t7[level].inst_size.fields.granu =
+				SMBIOS_CACHE_GRANU_1K;
+			priv->t7[level].inst_size2.data = 0;
+		}
+		priv->cache_socket_design[level] = pcache->socket_design;
+		smbios_cache_info_dump(&priv->t7[level]);
+	}
+	if (!level) /* no cache detected */
+		return -ENOSYS;
+
+	priv->cache_level = level;
+
 	return 0;
 }
 
diff --git a/drivers/sysinfo/smbios_plat.h b/drivers/sysinfo/smbios_plat.h
index 3576f492ecb..8439feb9fc5 100644
--- a/drivers/sysinfo/smbios_plat.h
+++ b/drivers/sysinfo/smbios_plat.h
@@ -13,6 +13,20 @@ 
  * sysinfo_plat and all sub data structure should be moved to <asm/sysinfo.h>
  * if we have this defined for each arch.
  */
+struct __packed cache_info {
+	char *socket_design;
+	union cache_config config;
+	u32 line_size;
+	u32 associativity;
+	u32 max_size;
+	u32 inst_size;
+	u8 cache_type;
+	union cache_sram_type supp_sram_type;
+	union cache_sram_type curr_sram_type;
+	u8 speed;
+	u8 err_corr_type;
+};
+
 struct __packed sys_info {
 	char *manufacturer;
 	char *prod_name;
@@ -89,12 +103,25 @@  struct sysinfo_plat {
 	struct baseboard_info board;
 	struct enclosure_info chassis;
 	struct processor_info *processor;
+	struct cache_info *cache;
 	/* add other sysinfo structure here */
 };
 
 #if CONFIG_IS_ENABLED(SYSINFO_SMBIOS)
+int sysinfo_get_cache_info(u8 level, struct cache_info *cache_info);
+void sysinfo_cache_info_default(struct cache_info *ci);
 int sysinfo_get_processor_info(struct processor_info *pinfo);
 #else
+static inline int sysinfo_get_cache_info(u8 level,
+					 struct cache_info *cache_info)
+{
+	return -ENOSYS;
+}
+
+static inline void sysinfo_cache_info_default(struct cache_info *ci)
+{
+}
+
 static inline int sysinfo_get_processor_info(struct processor_info *pinfo)
 {
 	return -ENOSYS;
diff --git a/include/smbios.h b/include/smbios.h
index f2269642268..267a672cefe 100644
--- a/include/smbios.h
+++ b/include/smbios.h
@@ -308,8 +308,120 @@  struct __packed smbios_type4 {
 	char eos[SMBIOS_STRUCT_EOS_BYTES];
 };
 
+/* Cache Information */
+
+#define SMBIOS_CACHE_SIZE_EXT_KB (2047 * 1024) /* 2047 MiB */
 #define SMBIOS_CACHE_HANDLE_NONE 0xffff
 
+#define SMBIOS_CACHE_SYSCACHE_TYPE_OTHER	1
+#define SMBIOS_CACHE_SYSCACHE_TYPE_UNKNOWN	2
+#define SMBIOS_CACHE_SYSCACHE_TYPE_INSTRUCTION	3
+#define SMBIOS_CACHE_SYSCACHE_TYPE_DATA		4
+#define SMBIOS_CACHE_SYSCACHE_TYPE_UNIFIED	5
+
+#define SMBIOS_CACHE_SPEED_UNKNOWN	0
+
+#define SMBIOS_CACHE_ERRCORR_OTHER	1
+#define SMBIOS_CACHE_ERRCORR_UNKNOWN	2
+#define SMBIOS_CACHE_ERRCORR_NONE	3
+#define SMBIOS_CACHE_ERRCORR_PARITY	4
+#define SMBIOS_CACHE_ERRCORR_SBITECC	5
+#define SMBIOS_CACHE_ERRCORR_MBITECC	6
+
+#define SMBIOS_CACHE_UNSOCKETED	0
+#define SMBIOS_CACHE_SOCKETED	1
+
+#define SMBIOS_CACHE_LOCATE_INTERNAL	0
+#define SMBIOS_CACHE_LOCATE_EXTERNAL	1
+#define SMBIOS_CACHE_LOCATE_RESERVED	2
+#define SMBIOS_CACHE_LOCATE_UNKNOWN	3
+
+#define SMBIOS_CACHE_DISABLED	0
+#define SMBIOS_CACHE_ENABLED	1
+
+#define SMBIOS_CACHE_OP_WT	0 /* Write Through */
+#define SMBIOS_CACHE_OP_WB	1 /* Write Back */
+#define SMBIOS_CACHE_OP_VAR	2 /* Varies with Memory Address */
+#define SMBIOS_CACHE_OP_UND	3 /* Unknown*/
+
+#define SMBIOS_CACHE_GRANU_1K	0
+#define SMBIOS_CACHE_GRANU_64K	1
+
+#define SMBIOS_CACHE_ASSOC_OTHER	1
+#define SMBIOS_CACHE_ASSOC_UNKNOWN	2
+#define SMBIOS_CACHE_ASSOC_DMAPPED	3
+#define SMBIOS_CACHE_ASSOC_2WAY		4
+#define SMBIOS_CACHE_ASSOC_4WAY		5
+#define SMBIOS_CACHE_ASSOC_FULLY	6
+#define SMBIOS_CACHE_ASSOC_8WAY		7
+#define SMBIOS_CACHE_ASSOC_16WAY	8
+#define SMBIOS_CACHE_ASSOC_12WAY	9
+#define SMBIOS_CACHE_ASSOC_24WAY	10
+#define SMBIOS_CACHE_ASSOC_32WAY	11
+#define SMBIOS_CACHE_ASSOC_48WAY	12
+#define SMBIOS_CACHE_ASSOC_64WAY	13
+#define SMBIOS_CACHE_ASSOC_20WAY	14
+
+union cache_config {
+	struct {
+		u16 level:3;
+		u16 bsocketed:1;
+		u16 rsvd0:1;
+		u16 locate:2;
+		u16 benabled:1;
+		u16 opmode:2;
+		u16 rsvd1:6;
+	} fields;
+	u16 data;
+};
+
+union cache_size_word {
+	struct {
+		u16 size:15;
+		u16 granu:1;
+	} fields;
+	u16 data;
+};
+
+union cache_size_dword {
+	struct {
+		u32 size:31;
+		u32 granu:1;
+	} fields;
+	u32 data;
+};
+
+union cache_sram_type {
+	struct {
+		u16 other:1;
+		u16 unknown:1;
+		u16 nonburst:1;
+		u16 burst:1;
+		u16 plburst:1;
+		u16 sync:1;
+		u16 async:1;
+		u16 rsvd:9;
+	} fields;
+	u16 data;
+};
+
+struct __packed smbios_type7 {
+	struct smbios_header hdr;
+	u8 socket_design;
+	union cache_config config;
+	union cache_size_word max_size;
+	union cache_size_word inst_size;
+	union cache_sram_type supp_sram_type;
+	union cache_sram_type curr_sram_type;
+	u8 speed;
+	u8 err_corr_type;
+	u8 sys_cache_type;
+	u8 associativity;
+	union cache_size_dword max_size2;
+	union cache_size_dword inst_size2;
+	char eos[SMBIOS_STRUCT_EOS_BYTES];
+};
+
 struct __packed smbios_type32 {
 	u8 type;
 	u8 length;
diff --git a/include/sysinfo.h b/include/sysinfo.h
index 6c9de7744c1..708bfc17ea6 100644
--- a/include/sysinfo.h
+++ b/include/sysinfo.h
@@ -11,6 +11,8 @@ 
 
 struct udevice;
 
+#define SYSINFO_CACHE_LVL_MAX 3
+
 /*
  * This uclass encapsulates hardware methods to gather information about a
  * sysinfo or a specific device such as hard-wired GPIOs on GPIO expanders,
@@ -111,6 +113,40 @@  enum sysinfo_id {
 	SYSINFO_ID_SMBIOS_PROCESSOR_THREAD_CNT2,
 	SYSINFO_ID_SMBIOS_PROCESSOR_THREAD_EN,
 
+	/*
+	 * Cache Information (Type 7)
+	 * Each of the id should reserve space for up to
+	 * SYSINFO_CACHE_LVL_MAX levels of cache
+	 */
+	SYSINFO_ID_SMBIOS_CACHE_LEVEL,
+	SYSINFO_ID_SMBIOS_CACHE_HANDLE,
+	SYSINFO_ID_SMBIOS_CACHE_INFO_START,
+	SYSINFO_ID_SMBIOS_CACHE_SOCKET = SYSINFO_ID_SMBIOS_CACHE_INFO_START,
+	SYSINFO_ID_SMBIOS_CACHE_CONFIG =
+		SYSINFO_ID_SMBIOS_CACHE_SOCKET + SYSINFO_CACHE_LVL_MAX,
+	SYSINFO_ID_SMBIOS_CACHE_MAX_SIZE =
+		SYSINFO_ID_SMBIOS_CACHE_CONFIG + SYSINFO_CACHE_LVL_MAX,
+	SYSINFO_ID_SMBIOS_CACHE_INST_SIZE =
+		SYSINFO_ID_SMBIOS_CACHE_MAX_SIZE + SYSINFO_CACHE_LVL_MAX,
+	SYSINFO_ID_SMBIOS_CACHE_SUPSRAM_TYPE =
+		SYSINFO_ID_SMBIOS_CACHE_INST_SIZE + SYSINFO_CACHE_LVL_MAX,
+	SYSINFO_ID_SMBIOS_CACHE_CURSRAM_TYPE =
+		SYSINFO_ID_SMBIOS_CACHE_SUPSRAM_TYPE + SYSINFO_CACHE_LVL_MAX,
+	SYSINFO_ID_SMBIOS_CACHE_SPEED =
+		SYSINFO_ID_SMBIOS_CACHE_CURSRAM_TYPE + SYSINFO_CACHE_LVL_MAX,
+	SYSINFO_ID_SMBIOS_CACHE_ERRCOR_TYPE =
+		SYSINFO_ID_SMBIOS_CACHE_SPEED + SYSINFO_CACHE_LVL_MAX,
+	SYSINFO_ID_SMBIOS_CACHE_SCACHE_TYPE =
+		SYSINFO_ID_SMBIOS_CACHE_ERRCOR_TYPE + SYSINFO_CACHE_LVL_MAX,
+	SYSINFO_ID_SMBIOS_CACHE_ASSOC =
+		SYSINFO_ID_SMBIOS_CACHE_SCACHE_TYPE + SYSINFO_CACHE_LVL_MAX,
+	SYSINFO_ID_SMBIOS_CACHE_MAX_SIZE2 =
+		SYSINFO_ID_SMBIOS_CACHE_ASSOC + SYSINFO_CACHE_LVL_MAX,
+	SYSINFO_ID_SMBIOS_CACHE_INST_SIZE2 =
+		SYSINFO_ID_SMBIOS_CACHE_MAX_SIZE2 + SYSINFO_CACHE_LVL_MAX,
+	SYSINFO_ID_SMBIOS_CACHE_INFO_END =
+		SYSINFO_ID_SMBIOS_CACHE_INST_SIZE2 + SYSINFO_CACHE_LVL_MAX - 1,
+
 	/* For show_board_info() */
 	SYSINFO_ID_BOARD_MODEL,
 	SYSINFO_ID_BOARD_MANUFACTURER,