acpi_parking_protocol.c 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. // SPDX-License-Identifier: GPL-2.0-only
  2. /*
  3. * ARM64 ACPI Parking Protocol implementation
  4. *
  5. * Authors: Lorenzo Pieralisi <[email protected]>
  6. * Mark Salter <[email protected]>
  7. */
  8. #include <linux/acpi.h>
  9. #include <linux/mm.h>
  10. #include <linux/types.h>
  11. #include <asm/cpu_ops.h>
  12. struct parking_protocol_mailbox {
  13. __le32 cpu_id;
  14. __le32 reserved;
  15. __le64 entry_point;
  16. };
  17. struct cpu_mailbox_entry {
  18. struct parking_protocol_mailbox __iomem *mailbox;
  19. phys_addr_t mailbox_addr;
  20. u8 version;
  21. u8 gic_cpu_id;
  22. };
  23. static struct cpu_mailbox_entry cpu_mailbox_entries[NR_CPUS];
  24. void __init acpi_set_mailbox_entry(int cpu,
  25. struct acpi_madt_generic_interrupt *p)
  26. {
  27. struct cpu_mailbox_entry *cpu_entry = &cpu_mailbox_entries[cpu];
  28. cpu_entry->mailbox_addr = p->parked_address;
  29. cpu_entry->version = p->parking_version;
  30. cpu_entry->gic_cpu_id = p->cpu_interface_number;
  31. }
  32. bool acpi_parking_protocol_valid(int cpu)
  33. {
  34. struct cpu_mailbox_entry *cpu_entry = &cpu_mailbox_entries[cpu];
  35. return cpu_entry->mailbox_addr && cpu_entry->version;
  36. }
  37. static int acpi_parking_protocol_cpu_init(unsigned int cpu)
  38. {
  39. pr_debug("%s: ACPI parked addr=%llx\n", __func__,
  40. cpu_mailbox_entries[cpu].mailbox_addr);
  41. return 0;
  42. }
  43. static int acpi_parking_protocol_cpu_prepare(unsigned int cpu)
  44. {
  45. return 0;
  46. }
  47. static int acpi_parking_protocol_cpu_boot(unsigned int cpu)
  48. {
  49. struct cpu_mailbox_entry *cpu_entry = &cpu_mailbox_entries[cpu];
  50. struct parking_protocol_mailbox __iomem *mailbox;
  51. u32 cpu_id;
  52. /*
  53. * Map mailbox memory with attribute device nGnRE (ie ioremap -
  54. * this deviates from the parking protocol specifications since
  55. * the mailboxes are required to be mapped nGnRnE; the attribute
  56. * discrepancy is harmless insofar as the protocol specification
  57. * is concerned).
  58. * If the mailbox is mistakenly allocated in the linear mapping
  59. * by FW ioremap will fail since the mapping will be prevented
  60. * by the kernel (it clashes with the linear mapping attributes
  61. * specifications).
  62. */
  63. mailbox = ioremap(cpu_entry->mailbox_addr, sizeof(*mailbox));
  64. if (!mailbox)
  65. return -EIO;
  66. cpu_id = readl_relaxed(&mailbox->cpu_id);
  67. /*
  68. * Check if firmware has set-up the mailbox entry properly
  69. * before kickstarting the respective cpu.
  70. */
  71. if (cpu_id != ~0U) {
  72. iounmap(mailbox);
  73. return -ENXIO;
  74. }
  75. /*
  76. * stash the mailbox address mapping to use it for further FW
  77. * checks in the postboot method
  78. */
  79. cpu_entry->mailbox = mailbox;
  80. /*
  81. * We write the entry point and cpu id as LE regardless of the
  82. * native endianness of the kernel. Therefore, any boot-loaders
  83. * that read this address need to convert this address to the
  84. * Boot-Loader's endianness before jumping.
  85. */
  86. writeq_relaxed(__pa_symbol(secondary_entry),
  87. &mailbox->entry_point);
  88. writel_relaxed(cpu_entry->gic_cpu_id, &mailbox->cpu_id);
  89. arch_send_wakeup_ipi_mask(cpumask_of(cpu));
  90. return 0;
  91. }
  92. static void acpi_parking_protocol_cpu_postboot(void)
  93. {
  94. int cpu = smp_processor_id();
  95. struct cpu_mailbox_entry *cpu_entry = &cpu_mailbox_entries[cpu];
  96. struct parking_protocol_mailbox __iomem *mailbox = cpu_entry->mailbox;
  97. u64 entry_point;
  98. entry_point = readq_relaxed(&mailbox->entry_point);
  99. /*
  100. * Check if firmware has cleared the entry_point as expected
  101. * by the protocol specification.
  102. */
  103. WARN_ON(entry_point);
  104. }
  105. const struct cpu_operations acpi_parking_protocol_ops = {
  106. .name = "parking-protocol",
  107. .cpu_init = acpi_parking_protocol_cpu_init,
  108. .cpu_prepare = acpi_parking_protocol_cpu_prepare,
  109. .cpu_boot = acpi_parking_protocol_cpu_boot,
  110. .cpu_postboot = acpi_parking_protocol_cpu_postboot
  111. };