0008-nb-intel-haswell-Add-native-raminit-scaffolding.patch 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. From 46cdec8cbce15ca11ad9a49a3ee415a78f781997 Mon Sep 17 00:00:00 2001
  2. From: Angel Pons <th3fanbus@gmail.com>
  3. Date: Sat, 7 May 2022 00:26:10 +0200
  4. Subject: [PATCH 08/26] nb/intel/haswell: Add native raminit scaffolding
  5. Implement some scaffolding for Haswell native raminit, like bootmode
  6. selection, handling of MRC cache and CPU detection.
  7. Change-Id: Icd96649fa045ea7f0f32ae9bfe1e60498d93975b
  8. Signed-off-by: Angel Pons <th3fanbus@gmail.com>
  9. ---
  10. .../intel/haswell/native_raminit/Makefile.inc | 1 +
  11. .../haswell/native_raminit/raminit_main.c | 104 ++++++++++
  12. .../haswell/native_raminit/raminit_native.c | 189 +++++++++++++++++-
  13. .../haswell/native_raminit/raminit_native.h | 34 ++++
  14. 4 files changed, 322 insertions(+), 6 deletions(-)
  15. create mode 100644 src/northbridge/intel/haswell/native_raminit/raminit_main.c
  16. create mode 100644 src/northbridge/intel/haswell/native_raminit/raminit_native.h
  17. diff --git a/src/northbridge/intel/haswell/native_raminit/Makefile.inc b/src/northbridge/intel/haswell/native_raminit/Makefile.inc
  18. index 8cfb4fb33e..90af951c5a 100644
  19. --- a/src/northbridge/intel/haswell/native_raminit/Makefile.inc
  20. +++ b/src/northbridge/intel/haswell/native_raminit/Makefile.inc
  21. @@ -1,3 +1,4 @@
  22. ## SPDX-License-Identifier: GPL-2.0-or-later
  23. +romstage-y += raminit_main.c
  24. romstage-y += raminit_native.c
  25. diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_main.c b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
  26. new file mode 100644
  27. index 0000000000..9b42c25b40
  28. --- /dev/null
  29. +++ b/src/northbridge/intel/haswell/native_raminit/raminit_main.c
  30. @@ -0,0 +1,104 @@
  31. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  32. +
  33. +#include <assert.h>
  34. +#include <console/console.h>
  35. +#include <cpu/intel/haswell/haswell.h>
  36. +#include <delay.h>
  37. +#include <device/pci_ops.h>
  38. +#include <northbridge/intel/haswell/chip.h>
  39. +#include <northbridge/intel/haswell/haswell.h>
  40. +#include <northbridge/intel/haswell/raminit.h>
  41. +#include <string.h>
  42. +#include <types.h>
  43. +
  44. +#include "raminit_native.h"
  45. +
  46. +struct task_entry {
  47. + enum raminit_status (*task)(struct sysinfo *);
  48. + bool is_enabled;
  49. + const char *name;
  50. +};
  51. +
  52. +static const struct task_entry cold_boot[] = {
  53. +};
  54. +
  55. +/* Return a generic stepping value to make stepping checks simpler */
  56. +static enum generic_stepping get_stepping(const uint32_t cpuid)
  57. +{
  58. + switch (cpuid) {
  59. + case CPUID_HASWELL_A0:
  60. + die("Haswell stepping A0 is not supported\n");
  61. + case CPUID_HASWELL_B0:
  62. + case CPUID_HASWELL_ULT_B0:
  63. + case CPUID_CRYSTALWELL_B0:
  64. + return STEPPING_B0;
  65. + case CPUID_HASWELL_C0:
  66. + case CPUID_HASWELL_ULT_C0:
  67. + case CPUID_CRYSTALWELL_C0:
  68. + return STEPPING_C0;
  69. + default:
  70. + /** TODO: Add Broadwell support someday **/
  71. + die("Unknown CPUID 0x%x\n", cpuid);
  72. + }
  73. +}
  74. +
  75. +static void initialize_ctrl(struct sysinfo *ctrl)
  76. +{
  77. + const struct northbridge_intel_haswell_config *cfg = config_of_soc();
  78. + const enum raminit_boot_mode bootmode = ctrl->bootmode;
  79. +
  80. + memset(ctrl, 0, sizeof(*ctrl));
  81. +
  82. + ctrl->cpu = cpu_get_cpuid();
  83. + ctrl->stepping = get_stepping(ctrl->cpu);
  84. + ctrl->dq_pins_interleaved = cfg->dq_pins_interleaved;
  85. + ctrl->bootmode = bootmode;
  86. +}
  87. +
  88. +static enum raminit_status try_raminit(struct sysinfo *ctrl)
  89. +{
  90. + const struct task_entry *const schedule = cold_boot;
  91. + const size_t length = ARRAY_SIZE(cold_boot);
  92. +
  93. + enum raminit_status status = RAMINIT_STATUS_UNSPECIFIED_ERROR;
  94. +
  95. + for (size_t i = 0; i < length; i++) {
  96. + const struct task_entry *const entry = &schedule[i];
  97. + assert(entry);
  98. + assert(entry->name);
  99. + if (!entry->is_enabled)
  100. + continue;
  101. +
  102. + assert(entry->task);
  103. + printk(RAM_DEBUG, "\nExecuting raminit task %s\n", entry->name);
  104. + status = entry->task(ctrl);
  105. + printk(RAM_DEBUG, "\n");
  106. + if (status) {
  107. + printk(BIOS_ERR, "raminit failed on step %s\n", entry->name);
  108. + break;
  109. + }
  110. + }
  111. +
  112. + return status;
  113. +}
  114. +
  115. +void raminit_main(const enum raminit_boot_mode bootmode)
  116. +{
  117. + /*
  118. + * The mighty_ctrl struct. Will happily nuke the pre-RAM stack
  119. + * if left unattended. Make it static and pass pointers to it.
  120. + */
  121. + static struct sysinfo mighty_ctrl;
  122. +
  123. + mighty_ctrl.bootmode = bootmode;
  124. + initialize_ctrl(&mighty_ctrl);
  125. +
  126. + /** TODO: Try more than once **/
  127. + enum raminit_status status = try_raminit(&mighty_ctrl);
  128. +
  129. + if (status != RAMINIT_STATUS_SUCCESS)
  130. + die("Memory initialization was met with utmost failure and misery\n");
  131. +
  132. + /** TODO: Implement the required magic **/
  133. + die("NATIVE RAMINIT: More Magic (tm) required.\n");
  134. +}
  135. diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.c b/src/northbridge/intel/haswell/native_raminit/raminit_native.c
  136. index b6efb6b40d..0869db3902 100644
  137. --- a/src/northbridge/intel/haswell/native_raminit/raminit_native.c
  138. +++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.c
  139. @@ -1,13 +1,45 @@
  140. /* SPDX-License-Identifier: GPL-2.0-or-later */
  141. +#include <arch/cpu.h>
  142. +#include <assert.h>
  143. +#include <cbmem.h>
  144. +#include <cf9_reset.h>
  145. #include <console/console.h>
  146. +#include <cpu/x86/msr.h>
  147. #include <delay.h>
  148. +#include <device/pci_ops.h>
  149. +#include <mrc_cache.h>
  150. #include <northbridge/intel/haswell/haswell.h>
  151. #include <northbridge/intel/haswell/raminit.h>
  152. #include <southbridge/intel/lynxpoint/me.h>
  153. #include <southbridge/intel/lynxpoint/pch.h>
  154. #include <types.h>
  155. +#include "raminit_native.h"
  156. +
  157. +static void wait_txt_clear(void)
  158. +{
  159. + const struct cpuid_result cpuid = cpuid_ext(1, 0);
  160. +
  161. + /* Check if TXT is supported */
  162. + if (!(cpuid.ecx & BIT(6)))
  163. + return;
  164. +
  165. + /* Some TXT public bit */
  166. + if (!(read32p(0xfed30010) & 1))
  167. + return;
  168. +
  169. + /* Wait for TXT clear */
  170. + do {} while (!(read8p(0xfed40000) & (1 << 7)));
  171. +}
  172. +
  173. +static enum raminit_boot_mode get_boot_mode(void)
  174. +{
  175. + const uint16_t pmcon_2 = pci_read_config16(PCH_LPC_DEV, GEN_PMCON_2);
  176. + const uint16_t bitmask = GEN_PMCON_2_DISB | GEN_PMCON_2_MEM_SR;
  177. + return (pmcon_2 & bitmask) == bitmask ? BOOTMODE_WARM : BOOTMODE_COLD;
  178. +}
  179. +
  180. static bool early_init_native(int s3resume)
  181. {
  182. printk(BIOS_DEBUG, "Starting native platform initialisation\n");
  183. @@ -24,6 +56,120 @@ static bool early_init_native(int s3resume)
  184. return cpu_replaced;
  185. }
  186. +#define MRC_CACHE_VERSION 1
  187. +
  188. +struct mrc_data {
  189. + const void *buffer;
  190. + size_t buffer_len;
  191. +};
  192. +
  193. +static void save_mrc_data(struct mrc_data *md)
  194. +{
  195. + mrc_cache_stash_data(MRC_TRAINING_DATA, MRC_CACHE_VERSION, md->buffer, md->buffer_len);
  196. +}
  197. +
  198. +static struct mrc_data prepare_mrc_cache(void)
  199. +{
  200. + struct mrc_data md = {0};
  201. + md.buffer = mrc_cache_current_mmap_leak(MRC_TRAINING_DATA,
  202. + MRC_CACHE_VERSION,
  203. + &md.buffer_len);
  204. + return md;
  205. +}
  206. +
  207. +static const char *const bm_names[] = {
  208. + "BOOTMODE_COLD",
  209. + "BOOTMODE_WARM",
  210. + "BOOTMODE_S3",
  211. + "BOOTMODE_FAST",
  212. +};
  213. +
  214. +static void clear_disb(void)
  215. +{
  216. + pci_and_config16(PCH_LPC_DEV, GEN_PMCON_2, ~GEN_PMCON_2_DISB);
  217. +}
  218. +
  219. +static void raminit_reset(void)
  220. +{
  221. + clear_disb();
  222. + system_reset();
  223. +}
  224. +
  225. +static enum raminit_boot_mode do_actual_raminit(
  226. + struct mrc_data *md,
  227. + const bool s3resume,
  228. + const bool cpu_replaced,
  229. + const enum raminit_boot_mode orig_bootmode)
  230. +{
  231. + enum raminit_boot_mode bootmode = orig_bootmode;
  232. +
  233. + bool save_data_valid = md->buffer && md->buffer_len == USHRT_MAX; /** TODO: sizeof() **/
  234. +
  235. + if (s3resume) {
  236. + if (bootmode == BOOTMODE_COLD) {
  237. + printk(BIOS_EMERG, "Memory may not be in self-refresh for S3 resume\n");
  238. + printk(BIOS_EMERG, "S3 resume and cold boot are mutually exclusive\n");
  239. + raminit_reset();
  240. + }
  241. + /* Only a true mad hatter would replace a CPU in S3 */
  242. + if (cpu_replaced) {
  243. + printk(BIOS_EMERG, "Oh no, CPU was replaced during S3\n");
  244. + /*
  245. + * No reason to continue, memory consistency is most likely lost
  246. + * and ME will probably request a reset through DID response too.
  247. + */
  248. + /** TODO: Figure out why past self commented this out **/
  249. + //raminit_reset();
  250. + }
  251. + bootmode = BOOTMODE_S3;
  252. + if (!save_data_valid) {
  253. + printk(BIOS_EMERG, "No training data, S3 resume is impossible\n");
  254. + /* Failed S3 resume, reset to come up cleanly */
  255. + raminit_reset();
  256. + }
  257. + }
  258. + if (!s3resume && cpu_replaced) {
  259. + printk(BIOS_NOTICE, "CPU was replaced, forcing a cold boot\n");
  260. + /*
  261. + * Looks like the ME will get angry if raminit takes too long.
  262. + * It will report that the CPU has been replaced on next boot.
  263. + * Try to continue anyway. This should not happen in most cases.
  264. + */
  265. + /** TODO: Figure out why past self commented this out **/
  266. + //save_data_valid = false;
  267. + }
  268. + if (bootmode == BOOTMODE_COLD) {
  269. + /* If possible, promote to a fast boot */
  270. + if (save_data_valid)
  271. + bootmode = BOOTMODE_FAST;
  272. +
  273. + clear_disb();
  274. + } else if (bootmode == BOOTMODE_WARM) {
  275. + /* If a warm reset happened before raminit is done, force a cold boot */
  276. + if (mchbar_read32(SSKPD) == 0 && mchbar_read32(SSKPD + 4) == 0) {
  277. + printk(BIOS_NOTICE, "Warm reset occurred early in cold boot\n");
  278. + save_data_valid = false;
  279. + }
  280. + if (!save_data_valid)
  281. + bootmode = BOOTMODE_COLD;
  282. + }
  283. + assert(save_data_valid != (bootmode == BOOTMODE_COLD));
  284. + if (save_data_valid) {
  285. + printk(BIOS_INFO, "Using cached memory parameters\n");
  286. + die("RAMINIT: Fast boot is not yet implemented\n");
  287. + }
  288. + printk(RAM_DEBUG, "Initial bootmode: %s\n", bm_names[orig_bootmode]);
  289. + printk(RAM_DEBUG, "Current bootmode: %s\n", bm_names[bootmode]);
  290. +
  291. + /*
  292. + * And now, the actual memory initialization thing.
  293. + */
  294. + printk(RAM_DEBUG, "\nStarting native raminit\n");
  295. + raminit_main(bootmode);
  296. +
  297. + return bootmode;
  298. +}
  299. +
  300. void perform_raminit(const int s3resume)
  301. {
  302. /*
  303. @@ -32,17 +178,48 @@ void perform_raminit(const int s3resume)
  304. */
  305. const bool cpu_replaced = early_init_native(s3resume);
  306. - (void)cpu_replaced;
  307. + wait_txt_clear();
  308. + wrmsr(0x2e6, (msr_t) {.lo = 0, .hi = 0});
  309. +
  310. + const enum raminit_boot_mode orig_bootmode = get_boot_mode();
  311. +
  312. + struct mrc_data md = prepare_mrc_cache();
  313. +
  314. + const enum raminit_boot_mode bootmode =
  315. + do_actual_raminit(&md, s3resume, cpu_replaced, orig_bootmode);
  316. +
  317. + /** TODO: report_memory_config **/
  318. - /** TODO: Move after raminit */
  319. if (intel_early_me_uma_size() > 0) {
  320. - /** TODO: Update status once raminit is implemented **/
  321. - uint8_t me_status = ME_INIT_STATUS_ERROR;
  322. + /*
  323. + * The 'other' success value is to report loss of memory
  324. + * consistency to ME if warm boot was downgraded to cold.
  325. + */
  326. + uint8_t me_status;
  327. + if (BOOTMODE_WARM == orig_bootmode && BOOTMODE_COLD == bootmode)
  328. + me_status = ME_INIT_STATUS_SUCCESS_OTHER;
  329. + else
  330. + me_status = ME_INIT_STATUS_SUCCESS;
  331. +
  332. + /** TODO: Remove this once raminit is implemented **/
  333. + me_status = ME_INIT_STATUS_ERROR;
  334. intel_early_me_init_done(me_status);
  335. }
  336. + post_code(0x3b);
  337. +
  338. intel_early_me_status();
  339. - /** TODO: Implement the required magic **/
  340. - die("NATIVE RAMINIT: More Magic (tm) required.\n");
  341. + const bool cbmem_was_initted = !cbmem_recovery(s3resume);
  342. + if (s3resume && !cbmem_was_initted) {
  343. + /* Failed S3 resume, reset to come up cleanly */
  344. + printk(BIOS_CRIT, "Failed to recover CBMEM in S3 resume.\n");
  345. + system_reset();
  346. + }
  347. +
  348. + /* Save training data on non-S3 resumes */
  349. + if (!s3resume)
  350. + save_mrc_data(&md);
  351. +
  352. + /** TODO: setup_sdram_meminfo **/
  353. }
  354. diff --git a/src/northbridge/intel/haswell/native_raminit/raminit_native.h b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
  355. new file mode 100644
  356. index 0000000000..885f0184f4
  357. --- /dev/null
  358. +++ b/src/northbridge/intel/haswell/native_raminit/raminit_native.h
  359. @@ -0,0 +1,34 @@
  360. +/* SPDX-License-Identifier: GPL-2.0-or-later */
  361. +
  362. +#ifndef HASWELL_RAMINIT_NATIVE_H
  363. +#define HASWELL_RAMINIT_NATIVE_H
  364. +
  365. +enum raminit_boot_mode {
  366. + BOOTMODE_COLD,
  367. + BOOTMODE_WARM,
  368. + BOOTMODE_S3,
  369. + BOOTMODE_FAST,
  370. +};
  371. +
  372. +enum raminit_status {
  373. + RAMINIT_STATUS_SUCCESS = 0,
  374. + RAMINIT_STATUS_UNSPECIFIED_ERROR, /** TODO: Deprecated in favor of specific values **/
  375. +};
  376. +
  377. +enum generic_stepping {
  378. + STEPPING_A0 = 1,
  379. + STEPPING_B0 = 2,
  380. + STEPPING_C0 = 3,
  381. +};
  382. +
  383. +struct sysinfo {
  384. + enum raminit_boot_mode bootmode;
  385. + enum generic_stepping stepping;
  386. + uint32_t cpu; /* CPUID value */
  387. +
  388. + bool dq_pins_interleaved;
  389. +};
  390. +
  391. +void raminit_main(enum raminit_boot_mode bootmode);
  392. +
  393. +#endif
  394. --
  395. 2.39.2