Commit | Line | Data |
---|---|---|
caab277b | 1 | // SPDX-License-Identifier: GPL-2.0-only |
5e89c55e LP |
2 | /* |
3 | * ARM64 ACPI Parking Protocol implementation | |
4 | * | |
5 | * Authors: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> | |
6 | * Mark Salter <msalter@redhat.com> | |
5e89c55e LP |
7 | */ |
8 | #include <linux/acpi.h> | |
2077be67 | 9 | #include <linux/mm.h> |
5e89c55e LP |
10 | #include <linux/types.h> |
11 | ||
12 | #include <asm/cpu_ops.h> | |
13 | ||
c1e4659b LP |
14 | struct parking_protocol_mailbox { |
15 | __le32 cpu_id; | |
16 | __le32 reserved; | |
17 | __le64 entry_point; | |
18 | }; | |
19 | ||
5e89c55e | 20 | struct cpu_mailbox_entry { |
c1e4659b | 21 | struct parking_protocol_mailbox __iomem *mailbox; |
5e89c55e LP |
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 | ||
5e89c55e LP |
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; | |
f0cda7e6 | 63 | u32 cpu_id; |
5e89c55e LP |
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 | ||
c1e4659b LP |
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 | ||
5e89c55e LP |
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 | */ | |
607289a7 | 102 | writeq_relaxed(__pa_symbol(secondary_entry), |
bde33977 | 103 | &mailbox->entry_point); |
5e89c55e LP |
104 | writel_relaxed(cpu_entry->gic_cpu_id, &mailbox->cpu_id); |
105 | ||
2b2d0a7a | 106 | arch_send_wakeup_ipi(cpu); |
5e89c55e | 107 | |
5e89c55e LP |
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]; | |
c1e4659b | 115 | struct parking_protocol_mailbox __iomem *mailbox = cpu_entry->mailbox; |
f0cda7e6 | 116 | u64 entry_point; |
5e89c55e | 117 | |
c0d109de | 118 | entry_point = readq_relaxed(&mailbox->entry_point); |
5e89c55e LP |
119 | /* |
120 | * Check if firmware has cleared the entry_point as expected | |
121 | * by the protocol specification. | |
122 | */ | |
123 | WARN_ON(entry_point); | |
5e89c55e LP |
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 | }; |