blob: f5c791b7da5a7d4faca7524bd22959de4f8b5562 [file] [log] [blame]
Angel Pons182dbde2020-04-02 23:49:05 +02001/* SPDX-License-Identifier: GPL-2.0-only */
Stefan Reinauer8e073822012-04-04 00:07:22 +02002
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 */
10
Furquan Shaikh76cedd22020-05-02 10:24:23 -070011#include <acpi/acpi.h>
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +030012#include <cf9_reset.h>
Kyösti Mälkki13f66502019-03-03 08:01:05 +020013#include <device/mmio.h>
Kyösti Mälkki21d6a272019-11-05 18:50:38 +020014#include <device/device.h>
15#include <device/pci.h>
Kyösti Mälkkif1b58b72019-03-01 13:43:02 +020016#include <device/pci_ops.h>
Stefan Reinauer8e073822012-04-04 00:07:22 +020017#include <console/console.h>
18#include <device/pci_ids.h>
Stefan Reinauer8e073822012-04-04 00:07:22 +020019#include <string.h>
Duncan Lauriec1c94352012-07-13 10:11:54 -070020#include <elog.h>
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +030021#include <option.h>
22#include <southbridge/intel/common/me.h>
Stefan Reinauer8e073822012-04-04 00:07:22 +020023
Stefan Reinauer8e073822012-04-04 00:07:22 +020024#include "me.h"
25#include "pch.h"
26
Angel Ponsc94bc8e2021-01-27 12:17:33 +010027static inline void print_cap(const char *name, int state)
28{
29 printk(BIOS_DEBUG, "ME Capability: %-41s : %sabled\n",
30 name, state ? " en" : "dis");
31}
32
33static void me_print_fw_version(mbp_fw_version_name *vers_name)
34{
35 if (!vers_name->major_version) {
36 printk(BIOS_ERR, "ME: mbp missing version report\n");
37 return;
38 }
39
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);
43}
44
Stefan Reinauer8e073822012-04-04 00:07:22 +020045/* Determine the path that we should take based on ME status */
Elyes HAOUASdc035282018-09-18 13:28:49 +020046static me_bios_path intel_me_path(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +020047{
48 me_bios_path path = ME_DISABLE_BIOS_PATH;
Angel Pons3f7bb7d2021-01-27 13:03:20 +010049 union me_hfs hfs;
50 union me_gmes gmes;
Stefan Reinauer8e073822012-04-04 00:07:22 +020051
Stefan Reinauer8e073822012-04-04 00:07:22 +020052 /* S3 wake skips all MKHI messages */
Kyösti Mälkkic3ed8862014-06-19 19:50:51 +030053 if (acpi_is_wakeup_s3())
Stefan Reinauer8e073822012-04-04 00:07:22 +020054 return ME_S3WAKE_BIOS_PATH;
Stefan Reinauer8e073822012-04-04 00:07:22 +020055
Angel Pons3f7bb7d2021-01-27 13:03:20 +010056 hfs.raw = pci_read_config32(dev, PCI_ME_HFS);
57 gmes.raw = pci_read_config32(dev, PCI_ME_GMES);
Stefan Reinauer8e073822012-04-04 00:07:22 +020058
59 /* Check and dump status */
60 intel_me_status(&hfs, &gmes);
61
Stefan Reinauer8e073822012-04-04 00:07:22 +020062 /* Check Current Working State */
63 switch (hfs.working_state) {
64 case ME_HFS_CWS_NORMAL:
65 path = ME_NORMAL_BIOS_PATH;
Stefan Reinauer8e073822012-04-04 00:07:22 +020066 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;
73 }
74
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;
86 }
87
Duncan Laurie5c88c6f2012-09-01 14:00:23 -070088 /* Check for any error code and valid firmware and MBP */
89 if (hfs.error_code || hfs.fpt_bad)
Stefan Reinauer8e073822012-04-04 00:07:22 +020090 path = ME_ERROR_BIOS_PATH;
91
Duncan Laurie5c88c6f2012-09-01 14:00:23 -070092 /* Check if the MBP is ready */
93 if (!gmes.mbp_rdy) {
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +030094 printk(BIOS_CRIT, "%s: mbp is not ready!\n", __func__);
Duncan Laurie5c88c6f2012-09-01 14:00:23 -070095 path = ME_ERROR_BIOS_PATH;
96 }
97
Kyösti Mälkkibe5317f2019-11-06 12:07:21 +020098 if (CONFIG(ELOG) && path != ME_NORMAL_BIOS_PATH) {
Duncan Laurie5c88c6f2012-09-01 14:00:23 -070099 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,
107 };
108 elog_add_event_byte(ELOG_TYPE_MANAGEMENT_ENGINE, path);
109 elog_add_event_raw(ELOG_TYPE_MANAGEMENT_ENGINE_EXT,
110 &data, sizeof(data));
111 }
Duncan Laurie5c88c6f2012-09-01 14:00:23 -0700112
Stefan Reinauer8e073822012-04-04 00:07:22 +0200113 return path;
114}
115
Angel Pons7f32df32020-06-02 13:36:57 +0200116static int intel_me_read_mbp(me_bios_payload *mbp_data);
117
Angel Ponsc94bc8e2021-01-27 12:17:33 +0100118/* Get ME Firmware Capabilities */
119static int mkhi_get_fwcaps(mefwcaps_sku *cap)
120{
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,
126 };
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),
132 };
133
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;
138 }
139 *cap = cap_msg.caps_sku;
140 return 0;
141}
142
143/* Get ME Firmware Capabilities */
144static void me_print_fwcaps(mbp_fw_caps *caps_section)
145{
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;
151 }
152
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);
169}
170
Stefan Reinauer8e073822012-04-04 00:07:22 +0200171/* Check whether ME is present and do basic init */
Elyes HAOUASdc035282018-09-18 13:28:49 +0200172static void intel_me_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200173{
174 me_bios_path path = intel_me_path(dev);
175 me_bios_payload mbp_data;
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +0300176 bool need_reset = false;
Angel Pons3f7bb7d2021-01-27 13:03:20 +0100177 union me_hfs hfs;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200178
179 /* Do initial setup and determine the BIOS path */
Angel Pons2e29c3b2020-08-10 15:47:28 +0200180 printk(BIOS_NOTICE, "ME: BIOS path: %s\n", me_get_bios_path_string(path));
Stefan Reinauer8e073822012-04-04 00:07:22 +0200181
Angel Pons88dcb312021-04-26 17:10:28 +0200182 u8 me_state = get_uint_option("me_state", 0);
183 u8 me_state_prev = get_uint_option("me_state_prev", 0);
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +0300184
185 printk(BIOS_DEBUG, "ME: me_state=%u, me_state_prev=%u\n", me_state, me_state_prev);
186
Stefan Reinauer8e073822012-04-04 00:07:22 +0200187 switch (path) {
188 case ME_S3WAKE_BIOS_PATH:
James Yea85d4a52020-02-22 20:30:49 +1100189#if CONFIG(HIDE_MEI_ON_ERROR)
190 case ME_ERROR_BIOS_PATH:
191#endif
Stefan Reinauer8e073822012-04-04 00:07:22 +0200192 intel_me_hide(dev);
193 break;
194
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 */
199
200 /* Prepare MEI MMIO interface */
201 if (intel_mei_setup(dev) < 0)
202 break;
203
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200204 if (intel_me_read_mbp(&mbp_data))
Stefan Reinauer8e073822012-04-04 00:07:22 +0200205 break;
206
Kyösti Mälkkic86fc8e2019-11-06 06:32:27 +0200207 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);
210 }
Duncan Laurie708f7312012-07-10 15:15:41 -0700211
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +0300212 /* 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");
221 }
222
223 break;
224 }
225
Duncan Laurie708f7312012-07-10 15:15:41 -0700226 /*
227 * Leave the ME unlocked in this path.
228 * It will be locked via SMI command later.
229 */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200230 break;
231
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +0300232 case ME_DISABLE_BIOS_PATH:
233 /* Bring ME out of Soft Temporary Disable mode, if needed */
Angel Pons3f7bb7d2021-01-27 13:03:20 +0100234 hfs.raw = pci_read_config32(dev, PCI_ME_HFS);
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +0300235 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");
240
241 exit_soft_temp_disable(dev);
242 exit_soft_temp_disable_wait(dev);
243
244 /*
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.
248 */
249 need_reset = true;
250 } else {
251 intel_me_hide(dev);
252 }
253 break;
254
James Yea85d4a52020-02-22 20:30:49 +1100255#if !CONFIG(HIDE_MEI_ON_ERROR)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200256 case ME_ERROR_BIOS_PATH:
James Yea85d4a52020-02-22 20:30:49 +1100257#endif
Stefan Reinauer8e073822012-04-04 00:07:22 +0200258 case ME_RECOVERY_BIOS_PATH:
Stefan Reinauer8e073822012-04-04 00:07:22 +0200259 case ME_FIRMWARE_UPDATE_BIOS_PATH:
Stefan Reinauer8e073822012-04-04 00:07:22 +0200260 break;
261 }
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +0300262
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;
Angel Pons88dcb312021-04-26 17:10:28 +0200267 set_uint_option("me_state_prev", new_state);
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +0300268 }
269
270 if (need_reset) {
271 set_global_reset(true);
272 full_reset();
273 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200274}
275
Stefan Reinauer8e073822012-04-04 00:07:22 +0200276static 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,
Angel Pons1fc0edd2020-05-31 00:03:28 +0200281 .ops_pci = &pci_dev_ops_pci,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200282};
283
284static const struct pci_driver intel_me __pci_driver = {
285 .ops = &device_ops,
Felix Singer43b7f412022-03-07 04:34:52 +0100286 .vendor = PCI_VID_INTEL,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200287 .device = 0x1e3a,
288};
289
290/******************************************************************************
291 * */
292static u32 me_to_host_words_pending(void)
293{
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);
300}
301
Stefan Reinauer8e073822012-04-04 00:07:22 +0200302/*
303 * mbp seems to be following its own flow, let's retrieve it in a dedicated
304 * function.
305 */
Angel Ponsc94bc8e2021-01-27 12:17:33 +0100306static int intel_me_read_mbp(me_bios_payload *mbp_data)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200307{
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;
313
314 me2host_pending = me_to_host_words_pending();
315 if (!me2host_pending) {
316 printk(BIOS_ERR, "ME: no mbp data!\n");
317 return -1;
318 }
319
320 /* we know for sure that at least the header is there */
321 mei_read_dword_ptr(&mbp_hdr, MEI_ME_CB_RW);
322
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;
330 }
331
332 me2host_pending--;
333 memset(mbp_data, 0, sizeof(*mbp_data));
334
335 while (mbp_hdr.num_entries--) {
Elyes HAOUAS448d9fb2018-05-22 12:51:27 +0200336 u32 *copy_addr;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200337 u32 copy_size, buffer_room;
338 void *p;
339
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;
344 }
345
346 mei_read_dword_ptr(&mbp_item_hdr, MEI_ME_CB_RW);
347
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;
353 }
354
355 me2host_pending -= mbp_item_hdr.length;
356
357 mbp_item_id = (((u32)mbp_item_hdr.item_id) << 8) +
358 mbp_item_hdr.app_id;
359
360 copy_size = mbp_item_hdr.length - 1;
361
362#define SET_UP_COPY(field) { copy_addr = (u32 *)&mbp_data->field; \
363 buffer_room = sizeof(mbp_data->field) / sizeof(u32); \
364 break; \
365 }
366
367 p = &mbp_item_hdr;
368 printk(BIOS_INFO, "ME: MBP item header %8.8x\n", *((u32*)p));
369
Elyes HAOUASf9de5a42018-05-03 17:21:02 +0200370 switch (mbp_item_id) {
Stefan Reinauer8e073822012-04-04 00:07:22 +0200371 case 0x101:
372 SET_UP_COPY(fw_version_name);
373
374 case 0x102:
375 SET_UP_COPY(icc_profile);
376
377 case 0x103:
378 SET_UP_COPY(at_state);
379
380 case 0x201:
381 mbp_data->fw_caps_sku.available = 1;
382 SET_UP_COPY(fw_caps_sku.fw_capabilities);
383
384 case 0x301:
385 SET_UP_COPY(rom_bist_data);
386
387 case 0x401:
388 SET_UP_COPY(platform_key);
389
390 case 0x501:
391 mbp_data->fw_plat_type.available = 1;
392 SET_UP_COPY(fw_plat_type.rule_data);
393
394 case 0x601:
395 SET_UP_COPY(mfsintegrity);
396
397 default:
Vladimir Serbinenkoafc8d982014-06-11 18:52:55 +0000398 printk(BIOS_ERR, "ME: unknown mbp item id 0x%x! Skipping\n",
Stefan Reinauer8e073822012-04-04 00:07:22 +0200399 mbp_item_id);
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200400 while (copy_size--)
Vladimir Serbinenkoafc8d982014-06-11 18:52:55 +0000401 read_cb();
402 continue;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200403 }
404
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;
410 }
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200411 while (copy_size--)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200412 *copy_addr++ = read_cb();
413 }
414
415 read_host_csr(&host);
416 host.interrupt_generate = 1;
417 write_host_csr(&host);
418
419 {
420 int cntr = 0;
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200421 while (host.interrupt_generate) {
Stefan Reinauer8e073822012-04-04 00:07:22 +0200422 read_host_csr(&host);
423 cntr++;
424 }
425 printk(BIOS_SPEW, "ME: mbp read OK after %d cycles\n", cntr);
426 }
427
428 return 0;
429}