xref: /aosp_15_r20/external/coreboot/src/drivers/ocp/dmi/smbios.c (revision b9411a12aaaa7e1e6a6fb7c5e057f44ee179a49c)
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include <console/console.h>
4 #include <device/device.h>
5 #include <drivers/ipmi/ipmi_ops.h>
6 #include <delay.h>
7 #include <cpu/x86/mp.h>
8 #include <timer.h>
9 #include <stdio.h>
10 #include <string.h>
11 #include <soc/soc_util.h>
12 #include <soc/util.h>
13 #include <smbios.h>
14 #include <types.h>
15 
16 #include "ocp_dmi.h"
17 
18 #define PPIN_STR_LEN 17
19 
20 struct fru_info_str fru_strings = {0};
21 /* The spec defines only at most 2 sockets */
22 msr_t xeon_sp_ppin[2] = {0};
23 static bool remote_ppin_done = false;
24 
25 /*
26  * Update SMBIOS type 0 ec version.
27  * For OCP platforms, BMC version is used to represent ec version.
28  * Refer to IPMI v2.0 spec, minor revision is defined as BCD encoded,
29  * format it accordingly.
30  */
smbios_ec_revision(uint8_t * ec_major_revision,uint8_t * ec_minor_revision)31 void smbios_ec_revision(uint8_t *ec_major_revision, uint8_t *ec_minor_revision)
32 {
33 	uint8_t bmc_major_revision, bmc_minor_revision;
34 
35 	ipmi_bmc_version(&bmc_major_revision, &bmc_minor_revision);
36 	*ec_major_revision = bmc_major_revision & 0x7f; /* bit[6:0] Major Firmware Revision */
37 	*ec_minor_revision = ((bmc_minor_revision / 16) * 10) + (bmc_minor_revision % 16);
38 }
39 
40 /* Override SMBIOS type 1 data. */
smbios_system_manufacturer(void)41 const char *smbios_system_manufacturer(void)
42 {
43 	if (fru_strings.prod_info.manufacturer != NULL)
44 		return (const char *)fru_strings.prod_info.manufacturer;
45 	else
46 		return CONFIG_MAINBOARD_SMBIOS_MANUFACTURER;
47 }
48 
smbios_system_product_name(void)49 const char *smbios_system_product_name(void)
50 {
51 	if (fru_strings.board_info.product_name != NULL)
52 		return (const char *)fru_strings.prod_info.product_name;
53 	else
54 		return CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME;
55 }
56 
smbios_system_serial_number(void)57 const char *smbios_system_serial_number(void)
58 {
59 	if (fru_strings.prod_info.serial_number != NULL)
60 		return (const char *)fru_strings.prod_info.serial_number;
61 	else
62 		return CONFIG_MAINBOARD_SERIAL_NUMBER;
63 }
64 
smbios_system_version(void)65 const char *smbios_system_version(void)
66 {
67 	if (fru_strings.prod_info.product_version != NULL)
68 		return (const char *)fru_strings.prod_info.product_version;
69 	else
70 		return CONFIG_MAINBOARD_VERSION;
71 }
72 
73 /* Override SMBIOS type 1 uuid from the value from BMC. */
smbios_system_set_uuid(u8 * uuid)74 void smbios_system_set_uuid(u8 *uuid)
75 {
76 	ipmi_get_system_guid(CONFIG_BMC_KCS_BASE, uuid);
77 }
78 
79 /* Override SMBIOS type 2 data. */
smbios_mainboard_version(void)80 const char *smbios_mainboard_version(void)
81 {
82 	if (fru_strings.board_info.part_number != NULL)
83 		return (const char *)fru_strings.board_info.part_number;
84 	else
85 		return CONFIG_MAINBOARD_VERSION;
86 }
87 
smbios_mainboard_manufacturer(void)88 const char *smbios_mainboard_manufacturer(void)
89 {
90 	if (fru_strings.board_info.manufacturer != NULL)
91 		return (const char *)fru_strings.board_info.manufacturer;
92 	else
93 		return CONFIG_MAINBOARD_SMBIOS_MANUFACTURER;
94 }
95 
smbios_mainboard_product_name(void)96 const char *smbios_mainboard_product_name(void)
97 {
98 	if (fru_strings.board_info.product_name != NULL)
99 		return (const char *)fru_strings.board_info.product_name;
100 	else
101 		return CONFIG_MAINBOARD_SMBIOS_PRODUCT_NAME;
102 }
103 
smbios_mainboard_serial_number(void)104 const char *smbios_mainboard_serial_number(void)
105 {
106 	if (fru_strings.board_info.serial_number != NULL)
107 		return (const char *)fru_strings.board_info.serial_number;
108 	else
109 		return CONFIG_MAINBOARD_SERIAL_NUMBER;
110 }
111 
112 /* Override SMBIOS type 2 and 3 asset_tag data. */
smbios_mainboard_asset_tag(void)113 const char *smbios_mainboard_asset_tag(void)
114 {
115 	if (fru_strings.prod_info.asset_tag != NULL)
116 		return (const char *)fru_strings.prod_info.asset_tag;
117 	else
118 		return "";
119 }
120 
121 /* Override SMBIOS type 3 data. */
smbios_mainboard_enclosure_type(void)122 smbios_enclosure_type smbios_mainboard_enclosure_type(void)
123 {
124 	/* SMBIOS System Enclosure or Chassis Types are values from 0 to 20h. */
125 	if (fru_strings.chassis_info.chassis_type <= 0x20)
126 		return fru_strings.chassis_info.chassis_type;
127 	else
128 		return SMBIOS_ENCLOSURE_RACK_MOUNT_CHASSIS;
129 }
130 
smbios_chassis_version(void)131 const char *smbios_chassis_version(void)
132 {
133 	if (fru_strings.chassis_info.chassis_partnumber != NULL)
134 		return fru_strings.chassis_info.chassis_partnumber;
135 	else
136 		return "";
137 }
138 
smbios_chassis_serial_number(void)139 const char *smbios_chassis_serial_number(void)
140 {
141 	if (fru_strings.chassis_info.serial_number != NULL)
142 		return fru_strings.chassis_info.serial_number;
143 	else
144 		return "";
145 }
146 
147 /* Override SMBIOS type 4 processor serial numbers from FRU Chassis custom data. */
smbios_processor_serial_number(void)148 const char *smbios_processor_serial_number(void)
149 {
150 	/* For now type 4 only creates for one CPU, so it can only write the serial number
151 	 * of CPU0.
152 	 */
153 	if (*fru_strings.chassis_info.chassis_custom != NULL)
154 		return *fru_strings.chassis_info.chassis_custom;
155 	else
156 		return "";
157 }
158 
read_remote_ppin(void * data)159 static void read_remote_ppin(void *data)
160 {
161 	*(msr_t *)data = read_msr_ppin();
162 	remote_ppin_done = true;
163 }
164 
wait_for_remote_ppin(void)165 static void wait_for_remote_ppin(void)
166 {
167 	struct stopwatch sw;
168 
169 	stopwatch_init_msecs_expire(&sw, 500);
170 	while (!stopwatch_expired(&sw)) {
171 		if (remote_ppin_done)
172 			break;
173 		mdelay(100);
174 	}
175 	if (stopwatch_expired(&sw))
176 		printk(BIOS_ERR, "Wait for read_remote_ppin() timeout\n");
177 }
178 
smbios_add_oem_string(u8 * start,const char * str)179 int smbios_add_oem_string(u8 *start, const char *str)
180 {
181 	int i = 1;
182 	char *p = (char *)start;
183 
184 	if (*str == '\0')
185 		return 0;
186 
187 	for (;;) {
188 		if (!*p) {
189 			strcpy(p, str);
190 			p += strlen(str);
191 			*p++ = '\0';
192 			*p++ = '\0';
193 			return i;
194 		}
195 
196 		p += strlen(p)+1;
197 		i++;
198 	}
199 }
200 
201 /* When the most significant 4 bits of PPIN hi/lo are 0, add '0' to the beginning */
ppin_string_fixup(int i,char * ppin)202 static void ppin_string_fixup(int i, char *ppin)
203 {
204 	if ((xeon_sp_ppin[i].hi & 0xf0000000) == 0) {
205 		if ((xeon_sp_ppin[i].lo & 0xf0000000) == 0)
206 			snprintf(ppin, PPIN_STR_LEN, "0%x0%x", xeon_sp_ppin[i].hi,
207 				xeon_sp_ppin[i].lo);
208 		else
209 			snprintf(ppin, PPIN_STR_LEN, "0%x%x", xeon_sp_ppin[i].hi,
210 				xeon_sp_ppin[i].lo);
211 	} else if ((xeon_sp_ppin[i].lo & 0xf0000000) == 0) {
212 		snprintf(ppin, PPIN_STR_LEN, "%x0%x", xeon_sp_ppin[i].hi, xeon_sp_ppin[i].lo);
213 	} else {
214 		snprintf(ppin, PPIN_STR_LEN, "%x%x", xeon_sp_ppin[i].hi, xeon_sp_ppin[i].lo);
215 	}
216 }
217 
218 /*
219  * Override SMBIOS type 11 OEM string 1 to string 6, the rest are project dependent
220  * and can be added in the mainboard code.
221  */
ocp_oem_smbios_strings(struct device * dev,struct smbios_type11 * t)222 void ocp_oem_smbios_strings(struct device *dev, struct smbios_type11 *t)
223 {
224 	char ppin[PPIN_STR_LEN];
225 
226 	/* Add OEM string 1 to 4 */
227 	if (fru_strings.board_info.custom_count > 0 &&
228 			*fru_strings.board_info.board_custom != NULL)
229 		t->count = smbios_add_oem_string(t->eos, *fru_strings.board_info.board_custom);
230 	else
231 		t->count = smbios_add_oem_string(t->eos, TBF);
232 
233 	if (fru_strings.prod_info.custom_count > 0 &&
234 			*fru_strings.prod_info.product_custom != NULL)
235 		t->count = smbios_add_oem_string(t->eos, *fru_strings.prod_info.product_custom);
236 	else
237 		t->count = smbios_add_oem_string(t->eos, TBF);
238 
239 	if (fru_strings.prod_info.custom_count > 1 &&
240 			*(fru_strings.prod_info.product_custom + 1) != NULL)
241 		t->count = smbios_add_oem_string(t->eos,
242 			*(fru_strings.prod_info.product_custom + 1));
243 	else
244 		t->count = smbios_add_oem_string(t->eos, TBF);
245 
246 	if (fru_strings.prod_info.custom_count > 2 &&
247 			*(fru_strings.prod_info.product_custom + 2) != NULL) {
248 		t->count = smbios_add_oem_string(t->eos,
249 			*(fru_strings.prod_info.product_custom + 2));
250 	} else {
251 		t->count = smbios_add_oem_string(t->eos, TBF);
252 	}
253 
254 	/* Add CPU0 PPIN to OEM string 5 */
255 	xeon_sp_ppin[0] = read_msr_ppin();
256 	ppin_string_fixup(0, ppin);
257 	t->count = smbios_add_oem_string(t->eos, ppin);
258 
259 	/* Add CPU1 PPIN to OEM string 6 */
260 	if (CONFIG_MAX_SOCKET == 2 && CONFIG(PARALLEL_MP_AP_WORK)) {
261 		/* Read the last CPU MSR */
262 		if (mp_run_on_aps(read_remote_ppin, (void *)&xeon_sp_ppin[1],
263 				get_platform_thread_count() - 1, 100 * USECS_PER_MSEC) !=
264 						CB_SUCCESS) {
265 			printk(BIOS_ERR, "Failed to read remote PPIN.\n");
266 			t->count = smbios_add_oem_string(t->eos, TBF);
267 		} else {
268 			/* Wait for read_remote_ppin() to finish because it's executed
269 			   in parallel */
270 			wait_for_remote_ppin();
271 			ppin_string_fixup(1, ppin);
272 			t->count = smbios_add_oem_string(t->eos, ppin);
273 		}
274 	} else {
275 		t->count = smbios_add_oem_string(t->eos, "0000");
276 	}
277 }
278