rhct.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * Copyright (C) 2022-2023, Ventana Micro Systems Inc
  4. * Author: Sunil V L <sunilvl@ventanamicro.com>
  5. *
  6. */
  7. #define pr_fmt(fmt) "ACPI: RHCT: " fmt
  8. #include <linux/acpi.h>
  9. #include <linux/bits.h>
  10. static struct acpi_table_rhct *acpi_get_rhct(void)
  11. {
  12. static struct acpi_table_header *rhct;
  13. acpi_status status;
  14. /*
  15. * RHCT will be used at runtime on every CPU, so we
  16. * don't need to call acpi_put_table() to release the table mapping.
  17. */
  18. if (!rhct) {
  19. status = acpi_get_table(ACPI_SIG_RHCT, 0, &rhct);
  20. if (ACPI_FAILURE(status)) {
  21. pr_warn_once("No RHCT table found\n");
  22. return NULL;
  23. }
  24. }
  25. return (struct acpi_table_rhct *)rhct;
  26. }
  27. /*
  28. * During early boot, the caller should call acpi_get_table() and pass its pointer to
  29. * these functions(and free up later). At run time, since this table can be used
  30. * multiple times, NULL may be passed in order to use the cached table.
  31. */
  32. int acpi_get_riscv_isa(struct acpi_table_header *table, unsigned int cpu, const char **isa)
  33. {
  34. struct acpi_rhct_node_header *node, *ref_node, *end;
  35. u32 size_hdr = sizeof(struct acpi_rhct_node_header);
  36. u32 size_hartinfo = sizeof(struct acpi_rhct_hart_info);
  37. struct acpi_rhct_hart_info *hart_info;
  38. struct acpi_rhct_isa_string *isa_node;
  39. struct acpi_table_rhct *rhct;
  40. u32 *hart_info_node_offset;
  41. u32 acpi_cpu_id = get_acpi_id_for_cpu(cpu);
  42. BUG_ON(acpi_disabled);
  43. if (!table) {
  44. rhct = acpi_get_rhct();
  45. if (!rhct)
  46. return -ENOENT;
  47. } else {
  48. rhct = (struct acpi_table_rhct *)table;
  49. }
  50. end = ACPI_ADD_PTR(struct acpi_rhct_node_header, rhct, rhct->header.length);
  51. for (node = ACPI_ADD_PTR(struct acpi_rhct_node_header, rhct, rhct->node_offset);
  52. node < end;
  53. node = ACPI_ADD_PTR(struct acpi_rhct_node_header, node, node->length)) {
  54. if (node->type == ACPI_RHCT_NODE_TYPE_HART_INFO) {
  55. hart_info = ACPI_ADD_PTR(struct acpi_rhct_hart_info, node, size_hdr);
  56. hart_info_node_offset = ACPI_ADD_PTR(u32, hart_info, size_hartinfo);
  57. if (acpi_cpu_id != hart_info->uid)
  58. continue;
  59. for (int i = 0; i < hart_info->num_offsets; i++) {
  60. ref_node = ACPI_ADD_PTR(struct acpi_rhct_node_header,
  61. rhct, hart_info_node_offset[i]);
  62. if (ref_node->type == ACPI_RHCT_NODE_TYPE_ISA_STRING) {
  63. isa_node = ACPI_ADD_PTR(struct acpi_rhct_isa_string,
  64. ref_node, size_hdr);
  65. *isa = isa_node->isa;
  66. return 0;
  67. }
  68. }
  69. }
  70. }
  71. return -1;
  72. }
  73. static void acpi_parse_hart_info_cmo_node(struct acpi_table_rhct *rhct,
  74. struct acpi_rhct_hart_info *hart_info,
  75. u32 *cbom_size, u32 *cboz_size, u32 *cbop_size)
  76. {
  77. u32 size_hartinfo = sizeof(struct acpi_rhct_hart_info);
  78. u32 size_hdr = sizeof(struct acpi_rhct_node_header);
  79. struct acpi_rhct_node_header *ref_node;
  80. struct acpi_rhct_cmo_node *cmo_node;
  81. u32 *hart_info_node_offset;
  82. hart_info_node_offset = ACPI_ADD_PTR(u32, hart_info, size_hartinfo);
  83. for (int i = 0; i < hart_info->num_offsets; i++) {
  84. ref_node = ACPI_ADD_PTR(struct acpi_rhct_node_header,
  85. rhct, hart_info_node_offset[i]);
  86. if (ref_node->type == ACPI_RHCT_NODE_TYPE_CMO) {
  87. cmo_node = ACPI_ADD_PTR(struct acpi_rhct_cmo_node,
  88. ref_node, size_hdr);
  89. if (cbom_size && cmo_node->cbom_size <= 30) {
  90. if (!*cbom_size)
  91. *cbom_size = BIT(cmo_node->cbom_size);
  92. else if (*cbom_size != BIT(cmo_node->cbom_size))
  93. pr_warn("CBOM size is not the same across harts\n");
  94. }
  95. if (cboz_size && cmo_node->cboz_size <= 30) {
  96. if (!*cboz_size)
  97. *cboz_size = BIT(cmo_node->cboz_size);
  98. else if (*cboz_size != BIT(cmo_node->cboz_size))
  99. pr_warn("CBOZ size is not the same across harts\n");
  100. }
  101. if (cbop_size && cmo_node->cbop_size <= 30) {
  102. if (!*cbop_size)
  103. *cbop_size = BIT(cmo_node->cbop_size);
  104. else if (*cbop_size != BIT(cmo_node->cbop_size))
  105. pr_warn("CBOP size is not the same across harts\n");
  106. }
  107. }
  108. }
  109. }
  110. /*
  111. * During early boot, the caller should call acpi_get_table() and pass its pointer to
  112. * these functions (and free up later). At run time, since this table can be used
  113. * multiple times, pass NULL so that the table remains in memory.
  114. */
  115. void acpi_get_cbo_block_size(struct acpi_table_header *table, u32 *cbom_size,
  116. u32 *cboz_size, u32 *cbop_size)
  117. {
  118. u32 size_hdr = sizeof(struct acpi_rhct_node_header);
  119. struct acpi_rhct_node_header *node, *end;
  120. struct acpi_rhct_hart_info *hart_info;
  121. struct acpi_table_rhct *rhct;
  122. if (acpi_disabled)
  123. return;
  124. if (table) {
  125. rhct = (struct acpi_table_rhct *)table;
  126. } else {
  127. rhct = acpi_get_rhct();
  128. if (!rhct)
  129. return;
  130. }
  131. if (cbom_size)
  132. *cbom_size = 0;
  133. if (cboz_size)
  134. *cboz_size = 0;
  135. if (cbop_size)
  136. *cbop_size = 0;
  137. end = ACPI_ADD_PTR(struct acpi_rhct_node_header, rhct, rhct->header.length);
  138. for (node = ACPI_ADD_PTR(struct acpi_rhct_node_header, rhct, rhct->node_offset);
  139. node < end;
  140. node = ACPI_ADD_PTR(struct acpi_rhct_node_header, node, node->length)) {
  141. if (node->type == ACPI_RHCT_NODE_TYPE_HART_INFO) {
  142. hart_info = ACPI_ADD_PTR(struct acpi_rhct_hart_info, node, size_hdr);
  143. acpi_parse_hart_info_cmo_node(rhct, hart_info, cbom_size,
  144. cboz_size, cbop_size);
  145. }
  146. }
  147. }