1 /* loapic.h - public LOAPIC APIs */
2
3 /*
4 * Copyright (c) 2015 Wind River Systems, Inc.
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 #ifndef ZEPHYR_INCLUDE_DRIVERS_LOAPIC_H_
10 #define ZEPHYR_INCLUDE_DRIVERS_LOAPIC_H_
11
12 #include <zephyr/arch/cpu.h>
13 #include <zephyr/arch/x86/msr.h>
14 #include <zephyr/sys/device_mmio.h>
15
16 /* Local APIC Register Offset */
17
18 #define LOAPIC_ID 0x020 /* Local APIC ID Reg */
19 #define LOAPIC_VER 0x030 /* Local APIC Version Reg */
20 #define LOAPIC_TPR 0x080 /* Task Priority Reg */
21 #define LOAPIC_APR 0x090 /* Arbitration Priority Reg */
22 #define LOAPIC_PPR 0x0a0 /* Processor Priority Reg */
23 #define LOAPIC_EOI 0x0b0 /* EOI Reg */
24 #define LOAPIC_LDR 0x0d0 /* Logical Destination Reg */
25 #define LOAPIC_DFR 0x0e0 /* Destination Format Reg */
26 #define LOAPIC_SVR 0x0f0 /* Spurious Interrupt Reg */
27 #define LOAPIC_ISR 0x100 /* In-service Reg */
28 #define LOAPIC_TMR 0x180 /* Trigger Mode Reg */
29 #define LOAPIC_IRR 0x200 /* Interrupt Request Reg */
30 #define LOAPIC_ESR 0x280 /* Error Status Reg */
31 #define LOAPIC_ICRLO 0x300 /* Interrupt Command Reg */
32 #define LOAPIC_ICRHI 0x310 /* Interrupt Command Reg */
33 #define LOAPIC_TIMER 0x320 /* LVT (Timer) */
34 #define LOAPIC_THERMAL 0x330 /* LVT (Thermal) */
35 #define LOAPIC_PMC 0x340 /* LVT (PMC) */
36 #define LOAPIC_LINT0 0x350 /* LVT (LINT0) */
37 #define LOAPIC_LINT1 0x360 /* LVT (LINT1) */
38 #define LOAPIC_ERROR 0x370 /* LVT (ERROR) */
39 #define LOAPIC_TIMER_ICR 0x380 /* Timer Initial Count Reg */
40 #define LOAPIC_TIMER_CCR 0x390 /* Timer Current Count Reg */
41 #define LOAPIC_TIMER_CONFIG 0x3e0 /* Timer Divide Config Reg */
42 #define LOAPIC_SELF_IPI 0x3f0 /* Self IPI Reg, only support in X2APIC mode */
43
44 #define LOAPIC_ICR_BUSY 0x00001000 /* delivery status: 1 = busy */
45
46 #define LOAPIC_ICR_IPI_OTHERS 0x000C4000U /* normal IPI to other CPUs */
47 #define LOAPIC_ICR_IPI_INIT 0x00004500U
48 #define LOAPIC_ICR_IPI_STARTUP 0x00004600U
49
50 #define LOAPIC_LVT_MASKED 0x00010000 /* mask */
51
52 /* Defined in intc_loapic.c */
53 #define LOAPIC_REGS_STR loapic_regs /* mmio device name */
54
55 #ifndef _ASMLANGUAGE
56
57 #ifdef __cplusplus
58 extern "C" {
59 #endif
60
61 DEVICE_MMIO_TOPLEVEL_DECLARE(LOAPIC_REGS_STR);
62
63 uint32_t z_loapic_irq_base(void);
64 void z_loapic_enable(unsigned char cpu_number);
65 void z_loapic_int_vec_set(unsigned int irq, unsigned int vector);
66 void z_loapic_irq_enable(unsigned int irq);
67 void z_loapic_irq_disable(unsigned int irq);
68
69 /**
70 * @brief Read 64-bit value from the local APIC in x2APIC mode.
71 *
72 * @param reg the LOAPIC register number to read (LOAPIC_*)
73 */
x86_read_x2apic(unsigned int reg)74 static inline uint64_t x86_read_x2apic(unsigned int reg)
75 {
76 reg >>= 4;
77 return z_x86_msr_read(X86_X2APIC_BASE_MSR + reg);
78 }
79
80 /**
81 * @brief Read 32-bit value from the local APIC in xAPIC (MMIO) mode.
82 *
83 * @param reg the LOAPIC register number to read (LOAPIC_*)
84 */
x86_read_xapic(unsigned int reg)85 static inline uint32_t x86_read_xapic(unsigned int reg)
86 {
87 mm_reg_t base;
88 base = DEVICE_MMIO_TOPLEVEL_GET(LOAPIC_REGS_STR);
89 return sys_read32(base + reg);
90 }
91
92 /**
93 * @brief Read value from the local APIC using the default mode.
94 *
95 * Returns a 32-bit value read from the local APIC, using the access
96 * method determined by CONFIG_X2APIC (either xAPIC or x2APIC). Note
97 * that 64-bit reads are only allowed in x2APIC mode and can only be
98 * done by calling x86_read_x2apic() directly. (This is intentional.)
99 *
100 * @param reg the LOAPIC register number to read (LOAPIC_*)
101 */
x86_read_loapic(unsigned int reg)102 static inline uint32_t x86_read_loapic(unsigned int reg)
103 {
104 #ifdef CONFIG_X2APIC
105 return x86_read_x2apic(reg);
106 #else
107 return x86_read_xapic(reg);
108 #endif
109 }
110
111 /**
112 * @brief Write 64-bit value to the local APIC in x2APIC mode.
113 *
114 * @param reg the LOAPIC register number to write (one of LOAPIC_*)
115 * @param val 64-bit value to write
116 */
x86_write_x2apic(unsigned int reg,uint64_t val)117 static inline void x86_write_x2apic(unsigned int reg, uint64_t val)
118 {
119 reg >>= 4;
120 z_x86_msr_write(X86_X2APIC_BASE_MSR + reg, val);
121 }
122
123 /**
124 * @brief Write 32-bit value to the local APIC in xAPIC (MMIO) mode.
125 *
126 * @param reg the LOAPIC register number to write (one of LOAPIC_*)
127 * @param val 32-bit value to write
128 */
x86_write_xapic(unsigned int reg,uint32_t val)129 static inline void x86_write_xapic(unsigned int reg, uint32_t val)
130 {
131 mm_reg_t base;
132 base = DEVICE_MMIO_TOPLEVEL_GET(LOAPIC_REGS_STR);
133 sys_write32(val, base + reg);
134 }
135
136 /**
137 * @brief Write 32-bit value to the local APIC using the default mode.
138 *
139 * Write a 32-bit value to the local APIC, using the access method
140 * determined by CONFIG_X2APIC (either xAPIC or x2APIC). Note that
141 * 64-bit writes are only available in x2APIC mode and can only be
142 * done by calling x86_write_x2apic() directly. (This is intentional.)
143 *
144 * @param reg the LOAPIC register number to write (one of LOAPIC_*)
145 * @param val 32-bit value to write
146 */
x86_write_loapic(unsigned int reg,uint32_t val)147 static inline void x86_write_loapic(unsigned int reg, uint32_t val)
148 {
149 #ifdef CONFIG_X2APIC
150 x86_write_x2apic(reg, val);
151 #else
152 x86_write_xapic(reg, val);
153 #endif
154 }
155
156 /**
157 * @brief Send an IPI.
158 *
159 * @param apic_id If applicable, the target CPU APIC ID (0 otherwise).
160 * @param ipi Type of IPI: one of the LOAPIC_ICR_IPI_* constants.
161 * @param vector If applicable, the target vector (0 otherwise).
162 */
z_loapic_ipi(uint8_t apic_id,uint32_t ipi,uint8_t vector)163 static inline void z_loapic_ipi(uint8_t apic_id, uint32_t ipi, uint8_t vector)
164 {
165 ipi |= vector;
166
167 #ifndef CONFIG_X2APIC
168 /*
169 * Legacy xAPIC mode: first wait for any previous IPI to be delivered.
170 */
171
172 while (x86_read_xapic(LOAPIC_ICRLO) & LOAPIC_ICR_BUSY) {
173 }
174
175 x86_write_xapic(LOAPIC_ICRHI, apic_id << 24);
176 x86_write_xapic(LOAPIC_ICRLO, ipi);
177 #else
178 /*
179 * x2APIC mode is greatly simplified: one write, no delivery status.
180 */
181
182 x86_write_x2apic(LOAPIC_ICRLO, (((uint64_t) apic_id) << 32) | ipi);
183 #endif
184 }
185
186 #ifdef __cplusplus
187 }
188 #endif
189
190 #endif /* _ASMLANGUAGE */
191
192 #endif /* ZEPHYR_INCLUDE_DRIVERS_LOAPIC_H_ */
193