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