Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/arm64/kernel/acpi_parking_protocol.c
26442 views
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
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
134