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