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