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