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 <arch/cpu.h>
13 #include <arch/x86/msr.h>
14 #include <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 
43 #define LOAPIC_ICR_BUSY		0x00001000	/* delivery status: 1 = busy */
44 
45 #define LOAPIC_ICR_IPI_OTHERS	0x000C4000U	/* normal IPI to other CPUs */
46 #define LOAPIC_ICR_IPI_INIT	0x00004500U
47 #define LOAPIC_ICR_IPI_STARTUP	0x00004600U
48 
49 #define LOAPIC_LVT_MASKED 0x00010000   /* mask */
50 
51 #ifndef _ASMLANGUAGE
52 
53 #ifdef __cplusplus
54 extern "C" {
55 #endif
56 
57 extern uint32_t z_loapic_irq_base(void);
58 extern void z_loapic_enable(unsigned char cpu_number);
59 extern void z_loapic_int_vec_set(unsigned int irq, unsigned int vector);
60 extern void z_loapic_irq_enable(unsigned int irq);
61 extern void z_loapic_irq_disable(unsigned int irq);
62 
63 /**
64  * @brief Read 64-bit value from the local APIC in x2APIC mode.
65  *
66  * @param reg the LOAPIC register number to read (LOAPIC_*)
67  */
x86_read_x2apic(unsigned int reg)68 static inline uint64_t x86_read_x2apic(unsigned int reg)
69 {
70 	reg >>= 4;
71 	return z_x86_msr_read(X86_X2APIC_BASE_MSR + reg);
72 }
73 
74 /* Defined in intc_loapic.c */
75 #ifdef DEVICE_MMIO_IS_IN_RAM
76 extern mm_reg_t z_loapic_regs;
77 #endif
78 
79 /**
80  * @brief Read 32-bit value from the local APIC in xAPIC (MMIO) mode.
81  *
82  * @param reg the LOAPIC register number to read (LOAPIC_*)
83  */
x86_read_xapic(unsigned int reg)84 static inline uint32_t x86_read_xapic(unsigned int reg)
85 {
86 	mm_reg_t base;
87 #ifdef DEVICE_MMIO_IS_IN_RAM
88 	base = z_loapic_regs;
89 #else
90 	base = CONFIG_LOAPIC_BASE_ADDRESS;
91 #endif
92 	return sys_read32(base + reg);
93 }
94 
95 /**
96  * @brief Read value from the local APIC using the default mode.
97  *
98  * Returns a 32-bit value read from the local APIC, using the access
99  * method determined by CONFIG_X2APIC (either xAPIC or x2APIC). Note
100  * that 64-bit reads are only allowed in x2APIC mode and can only be
101  * done by calling x86_read_x2apic() directly. (This is intentional.)
102  *
103  * @param reg the LOAPIC register number to read (LOAPIC_*)
104  */
x86_read_loapic(unsigned int reg)105 static inline uint32_t x86_read_loapic(unsigned int reg)
106 {
107 #ifdef CONFIG_X2APIC
108 	return x86_read_x2apic(reg);
109 #else
110 	return x86_read_xapic(reg);
111 #endif
112 }
113 
114 /**
115  * @brief Write 64-bit value to the local APIC in x2APIC mode.
116  *
117  * @param reg the LOAPIC register number to write (one of LOAPIC_*)
118  * @param val 64-bit value to write
119  */
x86_write_x2apic(unsigned int reg,uint64_t val)120 static inline void x86_write_x2apic(unsigned int reg, uint64_t val)
121 {
122 	reg >>= 4;
123 	z_x86_msr_write(X86_X2APIC_BASE_MSR + reg, val);
124 }
125 
126 /**
127  * @brief Write 32-bit value to the local APIC in xAPIC (MMIO) mode.
128  *
129  * @param reg the LOAPIC register number to write (one of LOAPIC_*)
130  * @param val 32-bit value to write
131  */
x86_write_xapic(unsigned int reg,uint32_t val)132 static inline void x86_write_xapic(unsigned int reg, uint32_t val)
133 {
134 	mm_reg_t base;
135 #ifdef DEVICE_MMIO_IS_IN_RAM
136 	base = z_loapic_regs;
137 #else
138 	base = CONFIG_LOAPIC_BASE_ADDRESS;
139 #endif
140 	sys_write32(val, base + reg);
141 }
142 
143 /**
144  * @brief Write 32-bit value to the local APIC using the default mode.
145  *
146  * Write a 32-bit value to the local APIC, using the access method
147  * determined by CONFIG_X2APIC (either xAPIC or x2APIC). Note that
148  * 64-bit writes are only available in x2APIC mode and can only be
149  * done by calling x86_write_x2apic() directly. (This is intentional.)
150  *
151  * @param reg the LOAPIC register number to write (one of LOAPIC_*)
152  * @param val 32-bit value to write
153  */
x86_write_loapic(unsigned int reg,uint32_t val)154 static inline void x86_write_loapic(unsigned int reg, uint32_t val)
155 {
156 #ifdef CONFIG_X2APIC
157 	x86_write_x2apic(reg, val);
158 #else
159 	x86_write_xapic(reg, val);
160 #endif
161 }
162 
163 /**
164  * @brief Send an IPI.
165  *
166  * @param apic_id If applicable, the target CPU APIC ID (0 otherwise).
167  * @param ipi Type of IPI: one of the LOAPIC_ICR_IPI_* constants.
168  * @param vector If applicable, the target vector (0 otherwise).
169  */
z_loapic_ipi(uint8_t apic_id,uint32_t ipi,uint8_t vector)170 static inline void z_loapic_ipi(uint8_t apic_id, uint32_t ipi, uint8_t vector)
171 {
172 	ipi |= vector;
173 
174 #ifndef CONFIG_X2APIC
175 	/*
176 	 * Legacy xAPIC mode: first wait for any previous IPI to be delivered.
177 	 */
178 
179 	while (x86_read_xapic(LOAPIC_ICRLO) & LOAPIC_ICR_BUSY) {
180 	}
181 
182 	x86_write_xapic(LOAPIC_ICRHI, apic_id << 24);
183 	x86_write_xapic(LOAPIC_ICRLO, ipi);
184 #else
185 	/*
186 	 * x2APIC mode is greatly simplified: one write, no delivery status.
187 	 */
188 
189 	x86_write_x2apic(LOAPIC_ICRLO, (((uint64_t) apic_id) << 32) | ipi);
190 #endif
191 }
192 
193 #ifdef __cplusplus
194 }
195 #endif
196 
197 #endif /* _ASMLANGUAGE */
198 
199 #endif /* ZEPHYR_INCLUDE_DRIVERS_LOAPIC_H_ */
200