blob: 24d11b2f0c2837c09b6dcbba78a092f724c6845d [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>
19#include <device/pci_def.h>
20#include <string.h>
Duncan Lauriec1c94352012-07-13 10:11:54 -070021#include <elog.h>
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +030022#include <halt.h>
23#include <option.h>
24#include <southbridge/intel/common/me.h>
Stefan Reinauer8e073822012-04-04 00:07:22 +020025
Stefan Reinauer8e073822012-04-04 00:07:22 +020026#include "me.h"
27#include "pch.h"
28
Angel Ponsc94bc8e2021-01-27 12:17:33 +010029static inline void print_cap(const char *name, int state)
30{
31 printk(BIOS_DEBUG, "ME Capability: %-41s : %sabled\n",
32 name, state ? " en" : "dis");
33}
34
35static void me_print_fw_version(mbp_fw_version_name *vers_name)
36{
37 if (!vers_name->major_version) {
38 printk(BIOS_ERR, "ME: mbp missing version report\n");
39 return;
40 }
41
42 printk(BIOS_DEBUG, "ME: found version %d.%d.%d.%d\n",
43 vers_name->major_version, vers_name->minor_version,
44 vers_name->hotfix_version, vers_name->build_version);
45}
46
Stefan Reinauer8e073822012-04-04 00:07:22 +020047/* Determine the path that we should take based on ME status */
Elyes HAOUASdc035282018-09-18 13:28:49 +020048static me_bios_path intel_me_path(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +020049{
50 me_bios_path path = ME_DISABLE_BIOS_PATH;
Angel Pons3f7bb7d2021-01-27 13:03:20 +010051 union me_hfs hfs;
52 union me_gmes gmes;
Stefan Reinauer8e073822012-04-04 00:07:22 +020053
Stefan Reinauer8e073822012-04-04 00:07:22 +020054 /* S3 wake skips all MKHI messages */
Kyösti Mälkkic3ed8862014-06-19 19:50:51 +030055 if (acpi_is_wakeup_s3())
Stefan Reinauer8e073822012-04-04 00:07:22 +020056 return ME_S3WAKE_BIOS_PATH;
Stefan Reinauer8e073822012-04-04 00:07:22 +020057
Angel Pons3f7bb7d2021-01-27 13:03:20 +010058 hfs.raw = pci_read_config32(dev, PCI_ME_HFS);
59 gmes.raw = pci_read_config32(dev, PCI_ME_GMES);
Stefan Reinauer8e073822012-04-04 00:07:22 +020060
61 /* Check and dump status */
62 intel_me_status(&hfs, &gmes);
63
Stefan Reinauer8e073822012-04-04 00:07:22 +020064 /* Check Current Working State */
65 switch (hfs.working_state) {
66 case ME_HFS_CWS_NORMAL:
67 path = ME_NORMAL_BIOS_PATH;
Stefan Reinauer8e073822012-04-04 00:07:22 +020068 break;
69 case ME_HFS_CWS_REC:
70 path = ME_RECOVERY_BIOS_PATH;
71 break;
72 default:
73 path = ME_DISABLE_BIOS_PATH;
74 break;
75 }
76
77 /* Check Current Operation Mode */
78 switch (hfs.operation_mode) {
79 case ME_HFS_MODE_NORMAL:
80 break;
81 case ME_HFS_MODE_DEBUG:
82 case ME_HFS_MODE_DIS:
83 case ME_HFS_MODE_OVER_JMPR:
84 case ME_HFS_MODE_OVER_MEI:
85 default:
86 path = ME_DISABLE_BIOS_PATH;
87 break;
88 }
89
Duncan Laurie5c88c6f2012-09-01 14:00:23 -070090 /* Check for any error code and valid firmware and MBP */
91 if (hfs.error_code || hfs.fpt_bad)
Stefan Reinauer8e073822012-04-04 00:07:22 +020092 path = ME_ERROR_BIOS_PATH;
93
Duncan Laurie5c88c6f2012-09-01 14:00:23 -070094 /* Check if the MBP is ready */
95 if (!gmes.mbp_rdy) {
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +030096 printk(BIOS_CRIT, "%s: mbp is not ready!\n", __func__);
Duncan Laurie5c88c6f2012-09-01 14:00:23 -070097 path = ME_ERROR_BIOS_PATH;
98 }
99
Kyösti Mälkkibe5317f2019-11-06 12:07:21 +0200100 if (CONFIG(ELOG) && path != ME_NORMAL_BIOS_PATH) {
Duncan Laurie5c88c6f2012-09-01 14:00:23 -0700101 struct elog_event_data_me_extended data = {
102 .current_working_state = hfs.working_state,
103 .operation_state = hfs.operation_state,
104 .operation_mode = hfs.operation_mode,
105 .error_code = hfs.error_code,
106 .progress_code = gmes.progress_code,
107 .current_pmevent = gmes.current_pmevent,
108 .current_state = gmes.current_state,
109 };
110 elog_add_event_byte(ELOG_TYPE_MANAGEMENT_ENGINE, path);
111 elog_add_event_raw(ELOG_TYPE_MANAGEMENT_ENGINE_EXT,
112 &data, sizeof(data));
113 }
Duncan Laurie5c88c6f2012-09-01 14:00:23 -0700114
Stefan Reinauer8e073822012-04-04 00:07:22 +0200115 return path;
116}
117
Angel Pons7f32df32020-06-02 13:36:57 +0200118static int intel_me_read_mbp(me_bios_payload *mbp_data);
119
Angel Ponsc94bc8e2021-01-27 12:17:33 +0100120/* Get ME Firmware Capabilities */
121static int mkhi_get_fwcaps(mefwcaps_sku *cap)
122{
123 u32 rule_id = 0;
124 struct me_fwcaps cap_msg;
125 struct mkhi_header mkhi = {
126 .group_id = MKHI_GROUP_ID_FWCAPS,
127 .command = MKHI_FWCAPS_GET_RULE,
128 };
129 struct mei_header mei = {
130 .is_complete = 1,
131 .host_address = MEI_HOST_ADDRESS,
132 .client_address = MEI_ADDRESS_MKHI,
133 .length = sizeof(mkhi) + sizeof(rule_id),
134 };
135
136 /* Send request and wait for response */
137 if (mei_sendrecv(&mei, &mkhi, &rule_id, &cap_msg, sizeof(cap_msg)) < 0) {
138 printk(BIOS_ERR, "ME: GET FWCAPS message failed\n");
139 return -1;
140 }
141 *cap = cap_msg.caps_sku;
142 return 0;
143}
144
145/* Get ME Firmware Capabilities */
146static void me_print_fwcaps(mbp_fw_caps *caps_section)
147{
148 mefwcaps_sku *cap = &caps_section->fw_capabilities;
149 if (!caps_section->available) {
150 printk(BIOS_ERR, "ME: mbp missing fwcaps report\n");
151 if (mkhi_get_fwcaps(cap))
152 return;
153 }
154
155 print_cap("Full Network manageability", cap->full_net);
156 print_cap("Regular Network manageability", cap->std_net);
157 print_cap("Manageability", cap->manageability);
158 print_cap("Small business technology", cap->small_business);
159 print_cap("Level III manageability", cap->l3manageability);
160 print_cap("IntelR Anti-Theft (AT)", cap->intel_at);
161 print_cap("IntelR Capability Licensing Service (CLS)", cap->intel_cls);
162 print_cap("IntelR Power Sharing Technology (MPC)", cap->intel_mpc);
163 print_cap("ICC Over Clocking", cap->icc_over_clocking);
164 print_cap("Protected Audio Video Path (PAVP)", cap->pavp);
165 print_cap("IPV6", cap->ipv6);
166 print_cap("KVM Remote Control (KVM)", cap->kvm);
167 print_cap("Outbreak Containment Heuristic (OCH)", cap->och);
168 print_cap("Virtual LAN (VLAN)", cap->vlan);
169 print_cap("TLS", cap->tls);
170 print_cap("Wireless LAN (WLAN)", cap->wlan);
171}
172
Stefan Reinauer8e073822012-04-04 00:07:22 +0200173/* Check whether ME is present and do basic init */
Elyes HAOUASdc035282018-09-18 13:28:49 +0200174static void intel_me_init(struct device *dev)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200175{
176 me_bios_path path = intel_me_path(dev);
177 me_bios_payload mbp_data;
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +0300178 bool need_reset = false;
Angel Pons3f7bb7d2021-01-27 13:03:20 +0100179 union me_hfs hfs;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200180
181 /* Do initial setup and determine the BIOS path */
Angel Pons2e29c3b2020-08-10 15:47:28 +0200182 printk(BIOS_NOTICE, "ME: BIOS path: %s\n", me_get_bios_path_string(path));
Stefan Reinauer8e073822012-04-04 00:07:22 +0200183
Angel Pons88dcb312021-04-26 17:10:28 +0200184 u8 me_state = get_uint_option("me_state", 0);
185 u8 me_state_prev = get_uint_option("me_state_prev", 0);
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +0300186
187 printk(BIOS_DEBUG, "ME: me_state=%u, me_state_prev=%u\n", me_state, me_state_prev);
188
Stefan Reinauer8e073822012-04-04 00:07:22 +0200189 switch (path) {
190 case ME_S3WAKE_BIOS_PATH:
James Yea85d4a52020-02-22 20:30:49 +1100191#if CONFIG(HIDE_MEI_ON_ERROR)
192 case ME_ERROR_BIOS_PATH:
193#endif
Stefan Reinauer8e073822012-04-04 00:07:22 +0200194 intel_me_hide(dev);
195 break;
196
197 case ME_NORMAL_BIOS_PATH:
198 /* Validate the extend register */
199 if (intel_me_extend_valid(dev) < 0)
200 break; /* TODO: force recovery mode */
201
202 /* Prepare MEI MMIO interface */
203 if (intel_mei_setup(dev) < 0)
204 break;
205
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200206 if (intel_me_read_mbp(&mbp_data))
Stefan Reinauer8e073822012-04-04 00:07:22 +0200207 break;
208
Kyösti Mälkkic86fc8e2019-11-06 06:32:27 +0200209 if (CONFIG_DEFAULT_CONSOLE_LOGLEVEL >= BIOS_DEBUG) {
210 me_print_fw_version(&mbp_data.fw_version_name);
211 me_print_fwcaps(&mbp_data.fw_caps_sku);
212 }
Duncan Laurie708f7312012-07-10 15:15:41 -0700213
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +0300214 /* Put ME in Software Temporary Disable Mode, if needed */
215 if (me_state == CMOS_ME_STATE_DISABLED
216 && CMOS_ME_STATE(me_state_prev) == CMOS_ME_STATE_NORMAL) {
217 printk(BIOS_INFO, "ME: disabling ME\n");
218 if (enter_soft_temp_disable()) {
219 enter_soft_temp_disable_wait();
220 need_reset = true;
221 } else {
222 printk(BIOS_ERR, "ME: failed to enter Soft Temporary Disable mode\n");
223 }
224
225 break;
226 }
227
Duncan Laurie708f7312012-07-10 15:15:41 -0700228 /*
229 * Leave the ME unlocked in this path.
230 * It will be locked via SMI command later.
231 */
Stefan Reinauer8e073822012-04-04 00:07:22 +0200232 break;
233
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +0300234 case ME_DISABLE_BIOS_PATH:
235 /* Bring ME out of Soft Temporary Disable mode, if needed */
Angel Pons3f7bb7d2021-01-27 13:03:20 +0100236 hfs.raw = pci_read_config32(dev, PCI_ME_HFS);
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +0300237 if (hfs.operation_mode == ME_HFS_MODE_DIS
238 && me_state == CMOS_ME_STATE_NORMAL
239 && (CMOS_ME_STATE(me_state_prev) == CMOS_ME_STATE_DISABLED
240 || !CMOS_ME_CHANGED(me_state_prev))) {
241 printk(BIOS_INFO, "ME: re-enabling ME\n");
242
243 exit_soft_temp_disable(dev);
244 exit_soft_temp_disable_wait(dev);
245
246 /*
247 * ME starts loading firmware immediately after writing to H_GS,
248 * but Lenovo BIOS performs a reboot after bringing ME back to
249 * Normal mode. Assume that global reset is needed.
250 */
251 need_reset = true;
252 } else {
253 intel_me_hide(dev);
254 }
255 break;
256
James Yea85d4a52020-02-22 20:30:49 +1100257#if !CONFIG(HIDE_MEI_ON_ERROR)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200258 case ME_ERROR_BIOS_PATH:
James Yea85d4a52020-02-22 20:30:49 +1100259#endif
Stefan Reinauer8e073822012-04-04 00:07:22 +0200260 case ME_RECOVERY_BIOS_PATH:
Stefan Reinauer8e073822012-04-04 00:07:22 +0200261 case ME_FIRMWARE_UPDATE_BIOS_PATH:
Stefan Reinauer8e073822012-04-04 00:07:22 +0200262 break;
263 }
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +0300264
265 /* To avoid boot loops if ME fails to get back from disabled mode,
266 set the 'changed' bit here. */
267 if (me_state != CMOS_ME_STATE(me_state_prev) || need_reset) {
268 u8 new_state = me_state | CMOS_ME_STATE_CHANGED;
Angel Pons88dcb312021-04-26 17:10:28 +0200269 set_uint_option("me_state_prev", new_state);
Evgeny Zinoviev833e9ba2019-11-21 21:47:31 +0300270 }
271
272 if (need_reset) {
273 set_global_reset(true);
274 full_reset();
275 }
Stefan Reinauer8e073822012-04-04 00:07:22 +0200276}
277
Stefan Reinauer8e073822012-04-04 00:07:22 +0200278static struct device_operations device_ops = {
279 .read_resources = pci_dev_read_resources,
280 .set_resources = pci_dev_set_resources,
281 .enable_resources = pci_dev_enable_resources,
282 .init = intel_me_init,
Angel Pons1fc0edd2020-05-31 00:03:28 +0200283 .ops_pci = &pci_dev_ops_pci,
Stefan Reinauer8e073822012-04-04 00:07:22 +0200284};
285
286static const struct pci_driver intel_me __pci_driver = {
287 .ops = &device_ops,
288 .vendor = PCI_VENDOR_ID_INTEL,
289 .device = 0x1e3a,
290};
291
292/******************************************************************************
293 * */
294static u32 me_to_host_words_pending(void)
295{
296 struct mei_csr me;
297 read_me_csr(&me);
298 if (!me.ready)
299 return 0;
300 return (me.buffer_write_ptr - me.buffer_read_ptr) &
301 (me.buffer_depth - 1);
302}
303
Stefan Reinauer8e073822012-04-04 00:07:22 +0200304/*
305 * mbp seems to be following its own flow, let's retrieve it in a dedicated
306 * function.
307 */
Angel Ponsc94bc8e2021-01-27 12:17:33 +0100308static int intel_me_read_mbp(me_bios_payload *mbp_data)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200309{
310 mbp_header mbp_hdr;
311 mbp_item_header mbp_item_hdr;
312 u32 me2host_pending;
313 u32 mbp_item_id;
314 struct mei_csr host;
315
316 me2host_pending = me_to_host_words_pending();
317 if (!me2host_pending) {
318 printk(BIOS_ERR, "ME: no mbp data!\n");
319 return -1;
320 }
321
322 /* we know for sure that at least the header is there */
323 mei_read_dword_ptr(&mbp_hdr, MEI_ME_CB_RW);
324
325 if ((mbp_hdr.num_entries > (mbp_hdr.mbp_size / 2)) ||
326 (me2host_pending < mbp_hdr.mbp_size)) {
327 printk(BIOS_ERR, "ME: mbp of %d entries, total size %d words"
328 " buffer contains %d words\n",
329 mbp_hdr.num_entries, mbp_hdr.mbp_size,
330 me2host_pending);
331 return -1;
332 }
333
334 me2host_pending--;
335 memset(mbp_data, 0, sizeof(*mbp_data));
336
337 while (mbp_hdr.num_entries--) {
Elyes HAOUAS448d9fb2018-05-22 12:51:27 +0200338 u32 *copy_addr;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200339 u32 copy_size, buffer_room;
340 void *p;
341
342 if (!me2host_pending) {
343 printk(BIOS_ERR, "ME: no mbp data %d entries to go!\n",
344 mbp_hdr.num_entries + 1);
345 return -1;
346 }
347
348 mei_read_dword_ptr(&mbp_item_hdr, MEI_ME_CB_RW);
349
350 if (mbp_item_hdr.length > me2host_pending) {
351 printk(BIOS_ERR, "ME: insufficient mbp data %d "
352 "entries to go!\n",
353 mbp_hdr.num_entries + 1);
354 return -1;
355 }
356
357 me2host_pending -= mbp_item_hdr.length;
358
359 mbp_item_id = (((u32)mbp_item_hdr.item_id) << 8) +
360 mbp_item_hdr.app_id;
361
362 copy_size = mbp_item_hdr.length - 1;
363
364#define SET_UP_COPY(field) { copy_addr = (u32 *)&mbp_data->field; \
365 buffer_room = sizeof(mbp_data->field) / sizeof(u32); \
366 break; \
367 }
368
369 p = &mbp_item_hdr;
370 printk(BIOS_INFO, "ME: MBP item header %8.8x\n", *((u32*)p));
371
Elyes HAOUASf9de5a42018-05-03 17:21:02 +0200372 switch (mbp_item_id) {
Stefan Reinauer8e073822012-04-04 00:07:22 +0200373 case 0x101:
374 SET_UP_COPY(fw_version_name);
375
376 case 0x102:
377 SET_UP_COPY(icc_profile);
378
379 case 0x103:
380 SET_UP_COPY(at_state);
381
382 case 0x201:
383 mbp_data->fw_caps_sku.available = 1;
384 SET_UP_COPY(fw_caps_sku.fw_capabilities);
385
386 case 0x301:
387 SET_UP_COPY(rom_bist_data);
388
389 case 0x401:
390 SET_UP_COPY(platform_key);
391
392 case 0x501:
393 mbp_data->fw_plat_type.available = 1;
394 SET_UP_COPY(fw_plat_type.rule_data);
395
396 case 0x601:
397 SET_UP_COPY(mfsintegrity);
398
399 default:
Vladimir Serbinenkoafc8d982014-06-11 18:52:55 +0000400 printk(BIOS_ERR, "ME: unknown mbp item id 0x%x! Skipping\n",
Stefan Reinauer8e073822012-04-04 00:07:22 +0200401 mbp_item_id);
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200402 while (copy_size--)
Vladimir Serbinenkoafc8d982014-06-11 18:52:55 +0000403 read_cb();
404 continue;
Stefan Reinauer8e073822012-04-04 00:07:22 +0200405 }
406
407 if (buffer_room != copy_size) {
408 printk(BIOS_ERR, "ME: buffer room %d != %d copy size"
409 " for item 0x%x!!!\n",
410 buffer_room, copy_size, mbp_item_id);
411 return -1;
412 }
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200413 while (copy_size--)
Stefan Reinauer8e073822012-04-04 00:07:22 +0200414 *copy_addr++ = read_cb();
415 }
416
417 read_host_csr(&host);
418 host.interrupt_generate = 1;
419 write_host_csr(&host);
420
421 {
422 int cntr = 0;
Elyes HAOUASba28e8d2016-08-31 19:22:16 +0200423 while (host.interrupt_generate) {
Stefan Reinauer8e073822012-04-04 00:07:22 +0200424 read_host_csr(&host);
425 cntr++;
426 }
427 printk(BIOS_SPEW, "ME: mbp read OK after %d cycles\n", cntr);
428 }
429
430 return 0;
431}