blob: da5fb71643f22cfa98fafdae4bd8fdd2b9ef6599 [file] [log] [blame]
Philipp Deppenwiesed8fe4432016-03-18 00:52:54 +01001/*
2 * This file is part of the coreboot project.
3 *
4 * Copyright (C) 2011 The Chromium OS Authors. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; version 2 of
9 * the License.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 */
16
17#include <pci/pci.h>
18#include <stdio.h>
19#include <string.h>
20#include <stdlib.h>
21#include <sys/io.h>
22#include <assert.h>
23#include <unistd.h>
24
25#include "me.h"
26#include "mmap.h"
27#include "intelmetool.h"
28
29#define read32(addr, off) ( *((uint32_t *) (addr + off)) )
30#define write32(addr, off, val) ( *((uint32_t *) (addr + off)) = val)
31
32/* Path that the BIOS should take based on ME state */
33/*
34static const char *me_bios_path_values[] = {
35 [ME_NORMAL_BIOS_PATH] = "Normal",
36 [ME_S3WAKE_BIOS_PATH] = "S3 Wake",
37 [ME_ERROR_BIOS_PATH] = "Error",
38 [ME_RECOVERY_BIOS_PATH] = "Recovery",
39 [ME_DISABLE_BIOS_PATH] = "Disable",
40 [ME_FIRMWARE_UPDATE_BIOS_PATH] = "Firmware Update",
41};
42*/
43
44/* MMIO base address for MEI interface */
45static uint32_t mei_base_address;
46static uint8_t* mei_mmap;
47
48static void mei_dump(void *ptr, int dword, int offset, const char *type)
49{
50 struct mei_csr *csr;
51
52
53 switch (offset) {
54 case MEI_H_CSR:
55 case MEI_ME_CSR_HA:
56 csr = ptr;
57/* if (!csr) {
58 printf("%-9s[%02x] : ", type, offset);
59 printf("ERROR: 0x%08x\n", dword);
60 break;
61 }
62 printf("%-9s[%02x] : ", type, offset);
63 printf("depth=%u read=%02u write=%02u ready=%u "
64 "reset=%u intgen=%u intstatus=%u intenable=%u\n", csr->buffer_depth,
65 csr->buffer_read_ptr, csr->buffer_write_ptr,
66 csr->ready, csr->reset, csr->interrupt_generate,
67 csr->interrupt_status, csr->interrupt_enable);
68*/ break;
69 case MEI_ME_CB_RW:
70 case MEI_H_CB_WW:
71 printf("%-9s[%02x] : ", type, offset);
72 printf("CB: 0x%08x\n", dword);
73 break;
74 default:
75 printf("%-9s[%02x] : ", type, offset);
76 printf("0x%08x\n", offset);
77 break;
78 }
79}
80
81/*
82 * ME/MEI access helpers using memcpy to avoid aliasing.
83 */
84
85static inline void mei_read_dword_ptr(void *ptr, uint32_t offset)
86{
87 uint32_t dword = read32(mei_mmap, offset);
88 memcpy(ptr, &dword, sizeof(dword));
89
90 if (debug) {
91 mei_dump(ptr, dword, offset, "READ");
92 }
93}
94
95static inline void mei_write_dword_ptr(void *ptr, uint32_t offset)
96{
97 uint32_t dword = 0;
98 memcpy(&dword, ptr, sizeof(dword));
99 write32(mei_mmap, offset, dword);
100
101 if (debug) {
102 mei_dump(ptr, dword, offset, "WRITE");
103 }
104}
105
106static inline void pci_read_dword_ptr(struct pci_dev *dev, void *ptr, uint32_t offset)
107{
108 uint32_t dword = pci_read_long(dev, offset);
109 memcpy(ptr, &dword, sizeof(dword));
110
111 if (debug) {
112 mei_dump(ptr, dword, offset, "PCI READ");
113 }
114}
115
116static inline void read_host_csr(struct mei_csr *csr)
117{
118 mei_read_dword_ptr(csr, MEI_H_CSR);
119}
120
121static inline void write_host_csr(struct mei_csr *csr)
122{
123 mei_write_dword_ptr(csr, MEI_H_CSR);
124}
125
126static inline void read_me_csr(struct mei_csr *csr)
127{
128 mei_read_dword_ptr(csr, MEI_ME_CSR_HA);
129}
130
131static inline void write_cb(uint32_t dword)
132{
133 write32(mei_mmap, MEI_H_CB_WW, dword);
134
135 if (debug) {
136 mei_dump(NULL, dword, MEI_H_CB_WW, "WRITE");
137 }
138}
139
140static inline uint32_t read_cb(void)
141{
142 uint32_t dword = read32(mei_mmap, MEI_ME_CB_RW);
143
144 if (debug) {
145 mei_dump(NULL, dword, MEI_ME_CB_RW, "READ");
146 }
147
148 return dword;
149}
150
151/* Wait for ME ready bit to be asserted */
152static int mei_wait_for_me_ready(void)
153{
154 struct mei_csr me;
155 unsigned try = ME_RETRY;
156
157 while (try--) {
158 read_me_csr(&me);
159 if (me.ready)
160 return 0;
161 usleep(ME_DELAY);
162 }
163
164 printf("ME: failed to become ready\n");
165 return -1;
166}
167
168void mei_reset(void)
169{
170 struct mei_csr host;
171
172 if (mei_wait_for_me_ready() < 0)
173 return;
174
175 /* Reset host and ME circular buffers for next message */
176 read_host_csr(&host);
177 host.reset = 1;
178 host.interrupt_generate = 1;
179 write_host_csr(&host);
180
181 if (mei_wait_for_me_ready() < 0)
182 return;
183
184 /* Re-init and indicate host is ready */
185 read_host_csr(&host);
186 host.interrupt_generate = 1;
187 host.ready = 1;
188 host.reset = 0;
189 write_host_csr(&host);
190}
191
192static int mei_send_msg(struct mei_header *mei, struct mkhi_header *mkhi,
193 void *req_data)
194{
195 struct mei_csr host;
196 unsigned ndata , n;
197 uint32_t *data;
198
199 /* Number of dwords to write, ignoring MKHI */
200 ndata = (mei->length) >> 2;
201
202 /* Pad non-dword aligned request message length */
203 if (mei->length & 3)
204 ndata++;
205 if (!ndata) {
206 printf("ME: request does not include MKHI\n");
207 return -1;
208 }
209 ndata++; /* Add MEI header */
210
211 /*
212 * Make sure there is still room left in the circular buffer.
213 * Reset the buffer pointers if the requested message will not fit.
214 */
215 read_host_csr(&host);
216 if ((host.buffer_depth - host.buffer_write_ptr) < ndata) {
217 printf("ME: circular buffer full, resetting...\n");
218 mei_reset();
219 read_host_csr(&host);
220 }
221
222 /*
223 * This implementation does not handle splitting large messages
224 * across multiple transactions. Ensure the requested length
225 * will fit in the available circular buffer depth.
226 */
227 if ((host.buffer_depth - host.buffer_write_ptr) < ndata) {
228 printf("ME: message (%u) too large for buffer (%u)\n",
229 ndata + 2, host.buffer_depth);
230 return -1;
231 }
232
233 /* Write MEI header */
234 mei_write_dword_ptr(mei, MEI_H_CB_WW);
235 ndata--;
236
237 /* Write MKHI header */
238 mei_write_dword_ptr(mkhi, MEI_H_CB_WW);
239 ndata--;
240
241 /* Write message data */
242 data = req_data;
243 for (n = 0; n < ndata; ++n)
244 write_cb(*data++);
245
246 /* Generate interrupt to the ME */
247 read_host_csr(&host);
248 host.interrupt_generate = 1;
249 write_host_csr(&host);
250
251 /* Make sure ME is ready after sending request data */
252 return mei_wait_for_me_ready();
253}
254
255static int mei_recv_msg(struct mei_header *mei, struct mkhi_header *mkhi,
256 void *rsp_data, uint32_t rsp_bytes)
257{
258 struct mei_header mei_rsp;
259 struct mkhi_header mkhi_rsp;
260 struct mei_csr me, host;
261 unsigned ndata, n;
262 unsigned expected;
263 uint32_t *data;
264
265 /* Total number of dwords to read from circular buffer */
266 expected = (rsp_bytes + sizeof(mei_rsp) + sizeof(mkhi_rsp)) >> 2;
267 if (rsp_bytes & 3)
268 expected++;
269
270 if (debug) {
271 printf("expected u32 = %d\n", expected);
272 }
273 /*
274 * The interrupt status bit does not appear to indicate that the
275 * message has actually been received. Instead we wait until the
276 * expected number of dwords are present in the circular buffer.
277 */
278 for (n = ME_RETRY; n; --n) {
279 read_me_csr(&me);
280 if ((me.buffer_write_ptr - me.buffer_read_ptr) >= expected)
281 //if (me.interrupt_generate && !me.interrupt_status)
282 //if (me.interrupt_status)
283 break;
284 usleep(ME_DELAY);
285 }
286 if (!n) {
287 printf("ME: timeout waiting for data: expected "
288 "%u, available %u\n", expected,
289 me.buffer_write_ptr - me.buffer_read_ptr);
290 return -1;
291 }
292 /* Read and verify MEI response header from the ME */
293 mei_read_dword_ptr(&mei_rsp, MEI_ME_CB_RW);
294 if (!mei_rsp.is_complete) {
295 printf("ME: response is not complete\n");
296 return -1;
297 }
298
299 /* Handle non-dword responses and expect at least MKHI header */
300 ndata = mei_rsp.length >> 2;
301 if (mei_rsp.length & 3)
302 ndata++;
303 if (ndata != (expected - 1)) { //XXX
304 printf("ME: response is missing data\n");
305 //return -1;
306 }
307
308 /* Read and verify MKHI response header from the ME */
309 mei_read_dword_ptr(&mkhi_rsp, MEI_ME_CB_RW);
310 if (!mkhi_rsp.is_response ||
311 mkhi->group_id != mkhi_rsp.group_id ||
312 mkhi->command != mkhi_rsp.command) {
313 printf("ME: invalid response, group %u ?= %u, "
314 "command %u ?= %u, is_response %u\n", mkhi->group_id,
315 mkhi_rsp.group_id, mkhi->command, mkhi_rsp.command,
316 mkhi_rsp.is_response);
317 //return -1;
318 }
319 ndata--; /* MKHI header has been read */
320
321 /* Make sure caller passed a buffer with enough space */
322 if (ndata != (rsp_bytes >> 2)) {
323 printf("ME: not enough room in response buffer: "
324 "%u != %u\n", ndata, rsp_bytes >> 2);
325 //return -1;
326 }
327
328 /* Read response data from the circular buffer */
329 data = rsp_data;
330 for (n = 0; n < ndata; ++n)
331 *data++ = read_cb();
332
333 /* Tell the ME that we have consumed the response */
334 read_host_csr(&host);
335 host.interrupt_status = 1;
336 host.interrupt_generate = 1;
337 write_host_csr(&host);
338
339 return mei_wait_for_me_ready();
340}
341
342static inline int mei_sendrecv(struct mei_header *mei, struct mkhi_header *mkhi,
343 void *req_data, void *rsp_data, uint32_t rsp_bytes)
344{
345 if (mei_send_msg(mei, mkhi, req_data) < 0)
346 return -1;
347 if (mei_recv_msg(mei, mkhi, rsp_data, rsp_bytes) < 0)
348 return -1;
349 return 0;
350}
351
352/* Send END OF POST message to the ME */
353/*
354static int mkhi_end_of_post(void)
355{
356 struct mkhi_header mkhi = {
357 .group_id = MKHI_GROUP_ID_GEN,
358 .command = MKHI_END_OF_POST,
359 };
360 struct mei_header mei = {
361 .is_complete = 1,
362 .host_address = MEI_HOST_ADDRESS,
363 .client_address = MEI_ADDRESS_MKHI,
364 .length = sizeof(mkhi),
365 };
366
367 if (mei_sendrecv(&mei, &mkhi, NULL, NULL, 0) < 0) {
368 printf("ME: END OF POST message failed\n");
369 return -1;
370 }
371
372 printf("ME: END OF POST message successful\n");
373 return 0;
374}
375*/
376
377/* Get ME firmware version */
378int mkhi_get_fw_version(void)
379{
380 uint32_t data = 0;
381 struct me_fw_version version = {0};
382
383 struct mkhi_header mkhi = {
384 .group_id = MKHI_GROUP_ID_GEN,
385 .command = GEN_GET_FW_VERSION,
386 .is_response = 0,
387 };
388
389 struct mei_header mei = {
390 .is_complete = 1,
391 .host_address = MEI_HOST_ADDRESS,
392 .client_address = MEI_ADDRESS_MKHI,
393 .length = sizeof(mkhi),
394 };
395
396#ifndef OLDARC
397 /* Send request and wait for response */
398 if (mei_sendrecv(&mei, &mkhi, &data, &version, sizeof(version) ) < 0) {
399 printf("ME: GET FW VERSION message failed\n");
400 return -1;
401 }
402 printf("ME: Firmware Version %u.%u.%u.%u (code) "
403 "%u.%u.%u.%u (recovery) "
404 "%u.%u.%u.%u (fitc)\n\n",
405 version.code_major, version.code_minor,
406 version.code_build_number, version.code_hot_fix,
407 version.recovery_major, version.recovery_minor,
408 version.recovery_build_number, version.recovery_hot_fix,
409 version.fitcmajor, version.fitcminor,
410 version.fitcbuildno, version.fitchotfix);
411#else
412 /* Send request and wait for response */
413 if (mei_sendrecv(&mei, &mkhi, &data, &version, 2*sizeof(uint32_t) ) < 0) {
414 printf("ME: GET FW VERSION message failed\n");
415 return -1;
416 }
417 printf("ME: Firmware Version %u.%u (code)\n\n"
418 version.code_major, version.code_minor);
419#endif
420 return 0;
421}
422
423static inline void print_cap(const char *name, int state)
424{
425 printf("ME Capability: %-30s : %s\n",
426 name, state ? "ON" : "OFF");
427}
428
429/* Get ME Firmware Capabilities */
430int mkhi_get_fwcaps(void)
431{
432 struct {
433 uint32_t rule_id;
434 uint32_t rule_len;
435
436 struct me_fwcaps cap;
437 } fwcaps;
438
439 fwcaps.rule_id = 0;
440 fwcaps.rule_len = 0;
441
442 struct mkhi_header mkhi = {
443 .group_id = MKHI_GROUP_ID_FWCAPS,
444 .command = MKHI_FWCAPS_GET_RULE,
445 .is_response = 0,
446 };
447 struct mei_header mei = {
448 .is_complete = 1,
449 .host_address = MEI_HOST_ADDRESS,
450 .client_address = MEI_ADDRESS_MKHI,
451 .length = sizeof(mkhi) + sizeof(fwcaps.rule_id),
452 };
453
454 /* Send request and wait for response */
455 if (mei_sendrecv(&mei, &mkhi, &fwcaps.rule_id, &fwcaps.cap, sizeof(fwcaps.cap)) < 0) {
456 printf("ME: GET FWCAPS message failed\n");
457 return -1;
458 }
459
460 print_cap("Full Network manageability ", fwcaps.cap.caps_sku.full_net);
461 print_cap("Regular Network manageability ", fwcaps.cap.caps_sku.std_net);
462 print_cap("Manageability ", fwcaps.cap.caps_sku.manageability);
463 print_cap("Small business technology ", fwcaps.cap.caps_sku.small_business);
464 print_cap("Level III manageability ", fwcaps.cap.caps_sku.l3manageability);
465 print_cap("IntelR Anti-Theft (AT) ", fwcaps.cap.caps_sku.intel_at);
466 print_cap("IntelR Capability Licensing Service (CLS) ",
467 fwcaps.cap.caps_sku.intel_cls);
468 print_cap("IntelR Power Sharing Technology (MPC) ",
469 fwcaps.cap.caps_sku.intel_mpc);
470 print_cap("ICC Over Clocking ", fwcaps.cap.caps_sku.icc_over_clocking);
471 print_cap("Protected Audio Video Path (PAVP) ", fwcaps.cap.caps_sku.pavp);
472 print_cap("IPV6 ", fwcaps.cap.caps_sku.ipv6);
473 print_cap("KVM Remote Control (KVM) ", fwcaps.cap.caps_sku.kvm);
474 print_cap("Outbreak Containment Heuristic (OCH) ", fwcaps.cap.caps_sku.och);
475 print_cap("Virtual LAN (VLAN) ", fwcaps.cap.caps_sku.vlan);
476 print_cap("TLS ", fwcaps.cap.caps_sku.tls);
477 print_cap("Wireless LAN (WLAN) ", fwcaps.cap.caps_sku.wlan);
478
479 return 0;
480}
481
482/* Tell ME to issue a global reset */
483uint32_t mkhi_global_reset(void)
484{
485 struct me_global_reset reset = {
486 .request_origin = GLOBAL_RESET_BIOS_POST,
487 .reset_type = CBM_RR_GLOBAL_RESET,
488 };
489 struct mkhi_header mkhi = {
490 .group_id = MKHI_GROUP_ID_CBM,
491 .command = MKHI_GLOBAL_RESET,
492 };
493 struct mei_header mei = {
494 .is_complete = 1,
495 .length = sizeof(mkhi) + sizeof(reset),
496 .host_address = MEI_HOST_ADDRESS,
497 .client_address = MEI_ADDRESS_MKHI,
498 };
499
500 printf("ME: Requesting global reset\n");
501
502 /* Send request and wait for response */
503 if (mei_sendrecv(&mei, &mkhi, &reset, NULL, 0) < 0) {
504 /* No response means reset will happen shortly... */
505 asm("hlt");
506 }
507
508 /* If the ME responded it rejected the reset request */
509 printf("ME: Global Reset failed\n");
510 return -1;
511}
512
513/* Tell ME thermal reporting parameters */
514/*
515void mkhi_thermal(void)
516{
517 struct me_thermal_reporting thermal = {
518 .polling_timeout = 2,
519 .smbus_ec_msglen = 1,
520 .smbus_ec_msgpec = 0,
521 .dimmnumber = 4,
522 };
523 struct mkhi_header mkhi = {
524 .group_id = MKHI_GROUP_ID_CBM,
525 .command = MKHI_THERMAL_REPORTING,
526 };
527 struct mei_header mei = {
528 .is_complete = 1,
529 .length = sizeof(mkhi) + sizeof(thermal),
530 .host_address = MEI_HOST_ADDRESS,
531 .client_address = MEI_ADDRESS_THERMAL,
532 };
533
534 printf("ME: Sending thermal reporting params\n");
535
536 mei_sendrecv(&mei, &mkhi, &thermal, NULL, 0);
537}
538*/
539
540/* Enable debug of internal ME memory */
541int mkhi_debug_me_memory(void *physaddr)
542{
543 uint32_t data = 0;
544
545 /* copy whole ME memory to a readable space */
546 struct me_debug_mem memory = {
547 .debug_phys = (uintptr_t)physaddr,
548 .debug_size = 0x2000000,
549 .me_phys = 0x20000000,
550 .me_size = 0x2000000,
551 };
552 struct mkhi_header mkhi = {
553 .group_id = MKHI_GROUP_ID_GEN,
554 .command = GEN_SET_DEBUG_MEM,
555 .is_response = 0,
556 };
557 struct mei_header mei = {
558 .is_complete = 1,
559 .length = sizeof(mkhi) + sizeof(memory),
560 .host_address = MEI_HOST_ADDRESS,
561 .client_address = MEI_ADDRESS_MKHI,
562 };
563
564 printf("ME: Debug memory to 0x%zx ...", (size_t)physaddr);
565 if (mei_sendrecv(&mei, &mkhi, &memory, &data, 0) < 0) {
566 printf("failed\n");
567 return -1;
568 } else {
569 printf("done\n");
570 }
571 return 0;
572}
573
574/* Prepare ME for MEI messages */
575uint32_t intel_mei_setup(struct pci_dev *dev)
576{
577 struct mei_csr host;
578 uint32_t reg32;
579 uint32_t pagerounded;
580
581 mei_base_address = dev->base_addr[0] & ~0xf;
582 pagerounded = mei_base_address & ~0xfff;
583 mei_mmap = map_physical(pagerounded, 0x2000) + mei_base_address - pagerounded;
584
585 /* Ensure Memory and Bus Master bits are set */
586 reg32 = pci_read_long(dev, PCI_COMMAND);
587 reg32 |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
588 pci_write_long(dev, PCI_COMMAND, reg32);
589
590 /* Clean up status for next message */
591 read_host_csr(&host);
592 host.interrupt_generate = 1;
593 host.ready = 1;
594 host.reset = 0;
595 write_host_csr(&host);
596
597 return 0;
598}
599
600/* Read the Extend register hash of ME firmware */
601int intel_me_extend_valid(struct pci_dev *dev)
602{
603 struct me_heres status;
604 uint32_t extend[8] = {0};
605 int i, count = 0;
606
607 pci_read_dword_ptr(dev, &status, PCI_ME_HERES);
608 if (!status.extend_feature_present) {
609 printf("ME: Extend Feature not present\n");
610 return -1;
611 }
612
613 if (!status.extend_reg_valid) {
614 printf("ME: Extend Register not valid\n");
615 return -1;
616 }
617
618 switch (status.extend_reg_algorithm) {
619 case PCI_ME_EXT_SHA1:
620 count = 5;
621 printf("ME: Extend SHA-1: ");
622 break;
623 case PCI_ME_EXT_SHA256:
624 count = 8;
625 printf("ME: Extend SHA-256: ");
626 break;
627 default:
628 printf("ME: Extend Algorithm %d unknown\n",
629 status.extend_reg_algorithm);
630 return -1;
631 }
632
633 for (i = 0; i < count; ++i) {
634 extend[i] = pci_read_long(dev, PCI_ME_HER(i));
635 printf("%08x", extend[i]);
636 }
637 printf("\n");
638
639 return 0;
640}