errata.c 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2021 Heiko Stuebner <[email protected]>
  4. */
  5. #include <linux/bug.h>
  6. #include <linux/kernel.h>
  7. #include <linux/memory.h>
  8. #include <linux/module.h>
  9. #include <linux/string.h>
  10. #include <linux/uaccess.h>
  11. #include <asm/alternative.h>
  12. #include <asm/cacheflush.h>
  13. #include <asm/errata_list.h>
  14. #include <asm/patch.h>
  15. #include <asm/vendorid_list.h>
  16. static bool errata_probe_pbmt(unsigned int stage,
  17. unsigned long arch_id, unsigned long impid)
  18. {
  19. if (!IS_ENABLED(CONFIG_ERRATA_THEAD_PBMT))
  20. return false;
  21. if (arch_id != 0 || impid != 0)
  22. return false;
  23. if (stage == RISCV_ALTERNATIVES_EARLY_BOOT ||
  24. stage == RISCV_ALTERNATIVES_MODULE)
  25. return true;
  26. return false;
  27. }
  28. static bool errata_probe_cmo(unsigned int stage,
  29. unsigned long arch_id, unsigned long impid)
  30. {
  31. if (!IS_ENABLED(CONFIG_ERRATA_THEAD_CMO))
  32. return false;
  33. if (arch_id != 0 || impid != 0)
  34. return false;
  35. if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
  36. return false;
  37. riscv_cbom_block_size = L1_CACHE_BYTES;
  38. riscv_noncoherent_supported();
  39. return true;
  40. }
  41. static u32 thead_errata_probe(unsigned int stage,
  42. unsigned long archid, unsigned long impid)
  43. {
  44. u32 cpu_req_errata = 0;
  45. if (errata_probe_pbmt(stage, archid, impid))
  46. cpu_req_errata |= BIT(ERRATA_THEAD_PBMT);
  47. if (errata_probe_cmo(stage, archid, impid))
  48. cpu_req_errata |= BIT(ERRATA_THEAD_CMO);
  49. return cpu_req_errata;
  50. }
  51. void __init_or_module thead_errata_patch_func(struct alt_entry *begin, struct alt_entry *end,
  52. unsigned long archid, unsigned long impid,
  53. unsigned int stage)
  54. {
  55. struct alt_entry *alt;
  56. u32 cpu_req_errata = thead_errata_probe(stage, archid, impid);
  57. u32 tmp;
  58. for (alt = begin; alt < end; alt++) {
  59. if (alt->vendor_id != THEAD_VENDOR_ID)
  60. continue;
  61. if (alt->errata_id >= ERRATA_THEAD_NUMBER)
  62. continue;
  63. tmp = (1U << alt->errata_id);
  64. if (cpu_req_errata & tmp) {
  65. /* On vm-alternatives, the mmu isn't running yet */
  66. if (stage == RISCV_ALTERNATIVES_EARLY_BOOT) {
  67. memcpy((void *)__pa_symbol(alt->old_ptr),
  68. (void *)__pa_symbol(alt->alt_ptr), alt->alt_len);
  69. } else {
  70. mutex_lock(&text_mutex);
  71. patch_text_nosync(alt->old_ptr, alt->alt_ptr, alt->alt_len);
  72. mutex_unlock(&text_mutex);
  73. }
  74. }
  75. }
  76. if (stage == RISCV_ALTERNATIVES_EARLY_BOOT)
  77. local_flush_icache_all();
  78. }