lib/smbios: Improve Type9
[coreboot2.git] / src / southbridge / intel / bd82x6x / me_8.x.c
blobf5c791b7da5a7d4faca7524bd22959de4f8b5562
1 /* SPDX-License-Identifier: GPL-2.0-only */
3 /*
4 * This is a ramstage driver for the Intel Management Engine found in the
5 * 6-series chipset. It handles the required boot-time messages over the
6 * MMIO-based Management Engine Interface to tell the ME that the BIOS is
7 * finished with POST. Additional messages are defined for debug but are
8 * not used unless the console loglevel is high enough.
9 */
11 #include <acpi/acpi.h>
12 #include <cf9_reset.h>
13 #include <device/mmio.h>
14 #include <device/device.h>
15 #include <device/pci.h>
16 #include <device/pci_ops.h>
17 #include <console/console.h>
18 #include <device/pci_ids.h>
19 #include <string.h>
20 #include <elog.h>
21 #include <option.h>
22 #include <southbridge/intel/common/me.h>
24 #include "me.h"
25 #include "pch.h"
27 static inline void print_cap(const char *name, int state)
29 printk(BIOS_DEBUG, "ME Capability: %-41s : %sabled\n",
30 name, state ? " en" : "dis");
33 static void me_print_fw_version(mbp_fw_version_name *vers_name)
35 if (!vers_name->major_version) {
36 printk(BIOS_ERR, "ME: mbp missing version report\n");
37 return;
40 printk(BIOS_DEBUG, "ME: found version %d.%d.%d.%d\n",
41 vers_name->major_version, vers_name->minor_version,
42 vers_name->hotfix_version, vers_name->build_version);
45 /* Determine the path that we should take based on ME status */
46 static me_bios_path intel_me_path(struct device *dev)
48 me_bios_path path = ME_DISABLE_BIOS_PATH;
49 union me_hfs hfs;
50 union me_gmes gmes;
52 /* S3 wake skips all MKHI messages */
53 if (acpi_is_wakeup_s3())
54 return ME_S3WAKE_BIOS_PATH;
56 hfs.raw = pci_read_config32(dev, PCI_ME_HFS);
57 gmes.raw = pci_read_config32(dev, PCI_ME_GMES);
59 /* Check and dump status */
60 intel_me_status(&hfs, &gmes);
62 /* Check Current Working State */
63 switch (hfs.working_state) {
64 case ME_HFS_CWS_NORMAL:
65 path = ME_NORMAL_BIOS_PATH;
66 break;
67 case ME_HFS_CWS_REC:
68 path = ME_RECOVERY_BIOS_PATH;
69 break;
70 default:
71 path = ME_DISABLE_BIOS_PATH;
72 break;
75 /* Check Current Operation Mode */
76 switch (hfs.operation_mode) {
77 case ME_HFS_MODE_NORMAL:
78 break;
79 case ME_HFS_MODE_DEBUG:
80 case ME_HFS_MODE_DIS:
81 case ME_HFS_MODE_OVER_JMPR:
82 case ME_HFS_MODE_OVER_MEI:
83 default:
84 path = ME_DISABLE_BIOS_PATH;
85 break;
88 /* Check for any error code and valid firmware and MBP */
89 if (hfs.error_code || hfs.fpt_bad)
90 path = ME_ERROR_BIOS_PATH;
92 /* Check if the MBP is ready */
93 if (!gmes.mbp_rdy) {
94 printk(BIOS_CRIT, "%s: mbp is not ready!\n", __func__);
95 path = ME_ERROR_BIOS_PATH;
98 if (CONFIG(ELOG) && path != ME_NORMAL_BIOS_PATH) {
99 struct elog_event_data_me_extended data = {
100 .current_working_state = hfs.working_state,
101 .operation_state = hfs.operation_state,
102 .operation_mode = hfs.operation_mode,
103 .error_code = hfs.error_code,
104 .progress_code = gmes.progress_code,
105 .current_pmevent = gmes.current_pmevent,
106 .current_state = gmes.current_state,
108 elog_add_event_byte(ELOG_TYPE_MANAGEMENT_ENGINE, path);
109 elog_add_event_raw(ELOG_TYPE_MANAGEMENT_ENGINE_EXT,
110 &data, sizeof(data));
113 return path;
116 static int intel_me_read_mbp(me_bios_payload *mbp_data);
118 /* Get ME Firmware Capabilities */
119 static int mkhi_get_fwcaps(mefwcaps_sku *cap)
121 u32 rule_id = 0;
122 struct me_fwcaps cap_msg;
123 struct mkhi_header mkhi = {
124 .group_id = MKHI_GROUP_ID_FWCAPS,
125 .command = MKHI_FWCAPS_GET_RULE,
127 struct mei_header mei = {
128 .is_complete = 1,
129 .host_address = MEI_HOST_ADDRESS,
130 .client_address = MEI_ADDRESS_MKHI,
131 .length = sizeof(mkhi) + sizeof(rule_id),
134 /* Send request and wait for response */
135 if (mei_sendrecv(&mei, &mkhi, &rule_id, &cap_msg, sizeof(cap_msg)) < 0) {
136 printk(BIOS_ERR, "ME: GET FWCAPS message failed\n");
137 return -1;
139 *cap = cap_msg.caps_sku;
140 return 0;
143 /* Get ME Firmware Capabilities */
144 static void me_print_fwcaps(mbp_fw_caps *caps_section)
146 mefwcaps_sku *cap = &caps_section->fw_capabilities;
147 if (!caps_section->available) {
148 printk(BIOS_ERR, "ME: mbp missing fwcaps report\n");
149 if (mkhi_get_fwcaps(cap))
150 return;
153 print_cap("Full Network manageability", cap->full_net);
154 print_cap("Regular Network manageability", cap->std_net);
155 print_cap("Manageability", cap->manageability);
156 print_cap("Small business technology", cap->small_business);
157 print_cap("Level III manageability", cap->l3manageability);
158 print_cap("IntelR Anti-Theft (AT)", cap->intel_at);
159 print_cap("IntelR Capability Licensing Service (CLS)", cap->intel_cls);
160 print_cap("IntelR Power Sharing Technology (MPC)", cap->intel_mpc);
161 print_cap("ICC Over Clocking", cap->icc_over_clocking);
162 print_cap("Protected Audio Video Path (PAVP)", cap->pavp);
163 print_cap("IPV6", cap->ipv6);
164 print_cap("KVM Remote Control (KVM)", cap->kvm);
165 print_cap("Outbreak Containment Heuristic (OCH)", cap->och);
166 print_cap("Virtual LAN (VLAN)", cap->vlan);
167 print_cap("TLS", cap->tls);
168 print_cap("Wireless LAN (WLAN)", cap->wlan);
171 /* Check whether ME is present and do basic init */
172 static void intel_me_init(struct device *dev)
174 me_bios_path path = intel_me_path(dev);
175 me_bios_payload mbp_data;
176 bool need_reset = false;
177 union me_hfs hfs;
179 /* Do initial setup and determine the BIOS path */
180 printk(BIOS_NOTICE, "ME: BIOS path: %s\n", me_get_bios_path_string(path));
182 u8 me_state = get_uint_option("me_state", 0);
183 u8 me_state_prev = get_uint_option("me_state_prev", 0);
185 printk(BIOS_DEBUG, "ME: me_state=%u, me_state_prev=%u\n", me_state, me_state_prev);
187 switch (path) {
188 case ME_S3WAKE_BIOS_PATH:
189 #if CONFIG(HIDE_MEI_ON_ERROR)
190 case ME_ERROR_BIOS_PATH:
191 #endif
192 intel_me_hide(dev);
193 break;
195 case ME_NORMAL_BIOS_PATH:
196 /* Validate the extend register */
197 if (intel_me_extend_valid(dev) < 0)
198 break; /* TODO: force recovery mode */
200 /* Prepare MEI MMIO interface */
201 if (intel_mei_setup(dev) < 0)
202 break;
204 if (intel_me_read_mbp(&mbp_data))
205 break;
207 if (CONFIG_DEFAULT_CONSOLE_LOGLEVEL >= BIOS_DEBUG) {
208 me_print_fw_version(&mbp_data.fw_version_name);
209 me_print_fwcaps(&mbp_data.fw_caps_sku);
212 /* Put ME in Software Temporary Disable Mode, if needed */
213 if (me_state == CMOS_ME_STATE_DISABLED
214 && CMOS_ME_STATE(me_state_prev) == CMOS_ME_STATE_NORMAL) {
215 printk(BIOS_INFO, "ME: disabling ME\n");
216 if (enter_soft_temp_disable()) {
217 enter_soft_temp_disable_wait();
218 need_reset = true;
219 } else {
220 printk(BIOS_ERR, "ME: failed to enter Soft Temporary Disable mode\n");
223 break;
227 * Leave the ME unlocked in this path.
228 * It will be locked via SMI command later.
230 break;
232 case ME_DISABLE_BIOS_PATH:
233 /* Bring ME out of Soft Temporary Disable mode, if needed */
234 hfs.raw = pci_read_config32(dev, PCI_ME_HFS);
235 if (hfs.operation_mode == ME_HFS_MODE_DIS
236 && me_state == CMOS_ME_STATE_NORMAL
237 && (CMOS_ME_STATE(me_state_prev) == CMOS_ME_STATE_DISABLED
238 || !CMOS_ME_CHANGED(me_state_prev))) {
239 printk(BIOS_INFO, "ME: re-enabling ME\n");
241 exit_soft_temp_disable(dev);
242 exit_soft_temp_disable_wait(dev);
245 * ME starts loading firmware immediately after writing to H_GS,
246 * but Lenovo BIOS performs a reboot after bringing ME back to
247 * Normal mode. Assume that global reset is needed.
249 need_reset = true;
250 } else {
251 intel_me_hide(dev);
253 break;
255 #if !CONFIG(HIDE_MEI_ON_ERROR)
256 case ME_ERROR_BIOS_PATH:
257 #endif
258 case ME_RECOVERY_BIOS_PATH:
259 case ME_FIRMWARE_UPDATE_BIOS_PATH:
260 break;
263 /* To avoid boot loops if ME fails to get back from disabled mode,
264 set the 'changed' bit here. */
265 if (me_state != CMOS_ME_STATE(me_state_prev) || need_reset) {
266 u8 new_state = me_state | CMOS_ME_STATE_CHANGED;
267 set_uint_option("me_state_prev", new_state);
270 if (need_reset) {
271 set_global_reset(true);
272 full_reset();
276 static struct device_operations device_ops = {
277 .read_resources = pci_dev_read_resources,
278 .set_resources = pci_dev_set_resources,
279 .enable_resources = pci_dev_enable_resources,
280 .init = intel_me_init,
281 .ops_pci = &pci_dev_ops_pci,
284 static const struct pci_driver intel_me __pci_driver = {
285 .ops = &device_ops,
286 .vendor = PCI_VID_INTEL,
287 .device = 0x1e3a,
290 /******************************************************************************
291 * */
292 static u32 me_to_host_words_pending(void)
294 struct mei_csr me;
295 read_me_csr(&me);
296 if (!me.ready)
297 return 0;
298 return (me.buffer_write_ptr - me.buffer_read_ptr) &
299 (me.buffer_depth - 1);
303 * mbp seems to be following its own flow, let's retrieve it in a dedicated
304 * function.
306 static int intel_me_read_mbp(me_bios_payload *mbp_data)
308 mbp_header mbp_hdr;
309 mbp_item_header mbp_item_hdr;
310 u32 me2host_pending;
311 u32 mbp_item_id;
312 struct mei_csr host;
314 me2host_pending = me_to_host_words_pending();
315 if (!me2host_pending) {
316 printk(BIOS_ERR, "ME: no mbp data!\n");
317 return -1;
320 /* we know for sure that at least the header is there */
321 mei_read_dword_ptr(&mbp_hdr, MEI_ME_CB_RW);
323 if ((mbp_hdr.num_entries > (mbp_hdr.mbp_size / 2)) ||
324 (me2host_pending < mbp_hdr.mbp_size)) {
325 printk(BIOS_ERR, "ME: mbp of %d entries, total size %d words"
326 " buffer contains %d words\n",
327 mbp_hdr.num_entries, mbp_hdr.mbp_size,
328 me2host_pending);
329 return -1;
332 me2host_pending--;
333 memset(mbp_data, 0, sizeof(*mbp_data));
335 while (mbp_hdr.num_entries--) {
336 u32 *copy_addr;
337 u32 copy_size, buffer_room;
338 void *p;
340 if (!me2host_pending) {
341 printk(BIOS_ERR, "ME: no mbp data %d entries to go!\n",
342 mbp_hdr.num_entries + 1);
343 return -1;
346 mei_read_dword_ptr(&mbp_item_hdr, MEI_ME_CB_RW);
348 if (mbp_item_hdr.length > me2host_pending) {
349 printk(BIOS_ERR, "ME: insufficient mbp data %d "
350 "entries to go!\n",
351 mbp_hdr.num_entries + 1);
352 return -1;
355 me2host_pending -= mbp_item_hdr.length;
357 mbp_item_id = (((u32)mbp_item_hdr.item_id) << 8) +
358 mbp_item_hdr.app_id;
360 copy_size = mbp_item_hdr.length - 1;
362 #define SET_UP_COPY(field) { copy_addr = (u32 *)&mbp_data->field; \
363 buffer_room = sizeof(mbp_data->field) / sizeof(u32); \
364 break; \
367 p = &mbp_item_hdr;
368 printk(BIOS_INFO, "ME: MBP item header %8.8x\n", *((u32*)p));
370 switch (mbp_item_id) {
371 case 0x101:
372 SET_UP_COPY(fw_version_name);
374 case 0x102:
375 SET_UP_COPY(icc_profile);
377 case 0x103:
378 SET_UP_COPY(at_state);
380 case 0x201:
381 mbp_data->fw_caps_sku.available = 1;
382 SET_UP_COPY(fw_caps_sku.fw_capabilities);
384 case 0x301:
385 SET_UP_COPY(rom_bist_data);
387 case 0x401:
388 SET_UP_COPY(platform_key);
390 case 0x501:
391 mbp_data->fw_plat_type.available = 1;
392 SET_UP_COPY(fw_plat_type.rule_data);
394 case 0x601:
395 SET_UP_COPY(mfsintegrity);
397 default:
398 printk(BIOS_ERR, "ME: unknown mbp item id 0x%x! Skipping\n",
399 mbp_item_id);
400 while (copy_size--)
401 read_cb();
402 continue;
405 if (buffer_room != copy_size) {
406 printk(BIOS_ERR, "ME: buffer room %d != %d copy size"
407 " for item 0x%x!!!\n",
408 buffer_room, copy_size, mbp_item_id);
409 return -1;
411 while (copy_size--)
412 *copy_addr++ = read_cb();
415 read_host_csr(&host);
416 host.interrupt_generate = 1;
417 write_host_csr(&host);
420 int cntr = 0;
421 while (host.interrupt_generate) {
422 read_host_csr(&host);
423 cntr++;
425 printk(BIOS_SPEW, "ME: mbp read OK after %d cycles\n", cntr);
428 return 0;