blob: 0a8f0555c99c534b5b701d6141e67be5a2df1ad8 [file] [log] [blame]
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -07001/*
2 * Copyright (c) 1984-2008, 2011-2015 Wind River Systems, Inc.
David B. Kinderac74d8b2017-01-18 17:01:01 -08003 * SPDX-License-Identifier: Apache-2.0
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -07004 */
5
Charles E. Youseaaecce42019-06-06 14:36:44 -07006/*
7 * driver for x86 CPU local APIC (as an interrupt controller)
Anas Nashifea0d0b22015-07-01 17:22:39 -04008 */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -07009
Flavio Santesb04cdcd2016-12-04 14:59:37 -060010#include <kernel.h>
Gustavo Lima Chaves9bb07ff2017-10-11 14:17:12 -070011#include <kernel_structs.h>
Dan Kalowskyc02dd342015-05-28 10:56:47 -070012#include <arch/cpu.h>
Kumar Gala78908162017-04-19 10:32:08 -050013#include <zephyr/types.h>
Jithu Joseph09a0c2f2016-05-06 21:55:51 -070014#include <string.h>
Anas Nashif5eb90ec2019-06-26 10:33:39 -040015#include <sys/__assert.h>
Charles E. Youse9a1e9272019-06-07 16:26:44 -070016#include <arch/x86/msr.h>
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070017
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070018#include <toolchain.h>
Anas Nashif397d29d2017-06-17 11:30:47 -040019#include <linker/sections.h>
Anas Nashif43a49332019-06-21 12:54:15 -040020#include <drivers/interrupt_controller/loapic.h> /* public API declarations */
Tomasz Bursztykadfe93862020-03-13 16:20:49 +010021#include <device.h>
Anas Nashif43a49332019-06-21 12:54:15 -040022#include <drivers/interrupt_controller/sysapic.h>
Tomasz Bursztyka915f4ac2021-03-09 19:54:42 +010023#include <drivers/interrupt_controller/ioapic.h>
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070024
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070025/* Local APIC Version Register Bits */
26
27#define LOAPIC_VERSION_MASK 0x000000ff /* LO APIC Version mask */
28#define LOAPIC_MAXLVT_MASK 0x00ff0000 /* LO APIC Max LVT mask */
29#define LOAPIC_PENTIUM4 0x00000014 /* LO APIC in Pentium4 */
30#define LOAPIC_LVT_PENTIUM4 5 /* LO APIC LVT - Pentium4 */
31#define LOAPIC_LVT_P6 4 /* LO APIC LVT - P6 */
32#define LOAPIC_LVT_P5 3 /* LO APIC LVT - P5 */
33
34/* Local APIC Vector Table Bits */
35
36#define LOAPIC_VECTOR 0x000000ff /* vectorNo */
37#define LOAPIC_MODE 0x00000700 /* delivery mode */
38#define LOAPIC_FIXED 0x00000000 /* delivery mode: FIXED */
39#define LOAPIC_SMI 0x00000200 /* delivery mode: SMI */
40#define LOAPIC_NMI 0x00000400 /* delivery mode: NMI */
41#define LOAPIC_EXT 0x00000700 /* delivery mode: ExtINT */
42#define LOAPIC_IDLE 0x00000000 /* delivery status: Idle */
43#define LOAPIC_PEND 0x00001000 /* delivery status: Pend */
44#define LOAPIC_HIGH 0x00000000 /* polarity: High */
45#define LOAPIC_LOW 0x00002000 /* polarity: Low */
46#define LOAPIC_REMOTE 0x00004000 /* remote IRR */
47#define LOAPIC_EDGE 0x00000000 /* trigger mode: Edge */
48#define LOAPIC_LEVEL 0x00008000 /* trigger mode: Level */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070049
50/* Local APIC Spurious-Interrupt Register Bits */
51
52#define LOAPIC_ENABLE 0x100 /* APIC Enabled */
53#define LOAPIC_FOCUS_DISABLE 0x200 /* Focus Processor Checking */
54
Andrew Boiec25d6c52015-12-09 14:53:41 -080055#if CONFIG_LOAPIC_SPURIOUS_VECTOR_ID == -1
56#define LOAPIC_SPURIOUS_VECTOR_ID (CONFIG_IDT_NUM_VECTORS - 1)
57#else
58#define LOAPIC_SPURIOUS_VECTOR_ID CONFIG_LOAPIC_SPURIOUS_VECTOR_ID
59#endif
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070060
Jithu Joseph09a0c2f2016-05-06 21:55:51 -070061#define LOPIC_SSPND_BITS_PER_IRQ 1 /* Just the one for enable disable*/
62#define LOPIC_SUSPEND_BITS_REQD (ROUND_UP((LOAPIC_IRQ_COUNT * LOPIC_SSPND_BITS_PER_IRQ), 32))
Anas Nashifdd931f92020-09-01 18:31:40 -040063#ifdef CONFIG_PM_DEVICE
Gerard Marull-Paretas3863be02021-05-03 17:26:38 +020064#include <pm/device.h>
Daniel Leunge4987482021-03-17 13:47:56 -070065__pinned_bss
Kumar Galaa1b77fd2020-05-27 11:26:57 -050066uint32_t loapic_suspend_buf[LOPIC_SUSPEND_BITS_REQD / 32] = {0};
Jithu Joseph09a0c2f2016-05-06 21:55:51 -070067#endif
68
Andrew Boieee3c50b2020-06-26 12:09:01 -070069#ifdef DEVICE_MMIO_IS_IN_RAM
Daniel Leunge4987482021-03-17 13:47:56 -070070__pinned_bss
Andrew Boieee3c50b2020-06-26 12:09:01 -070071mm_reg_t z_loapic_regs;
72#endif
73
Daniel Leunge4987482021-03-17 13:47:56 -070074__pinned_func
Andrew Boieee3c50b2020-06-26 12:09:01 -070075void send_eoi(void)
76{
77 x86_write_xapic(LOAPIC_EOI, 0);
78}
79
Anas Nashifea0d0b22015-07-01 17:22:39 -040080/**
Charles E. Yousea981f512019-09-28 16:58:22 -040081 * @brief Enable and initialize the local APIC.
Anas Nashifea0d0b22015-07-01 17:22:39 -040082 *
Charles E. Yousea981f512019-09-28 16:58:22 -040083 * Called from early assembly layer (e.g., crt0.S).
Anas Nashifea0d0b22015-07-01 17:22:39 -040084 */
Daniel Leunge4987482021-03-17 13:47:56 -070085__pinned_func
Zide Chend27f6cb2020-02-10 14:09:05 -080086void z_loapic_enable(unsigned char cpu_number)
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070087{
Kumar Galaa1b77fd2020-05-27 11:26:57 -050088 int32_t loApicMaxLvt; /* local APIC Max LVT */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070089
Andrew Boieee3c50b2020-06-26 12:09:01 -070090#ifdef DEVICE_MMIO_IS_IN_RAM
91 device_map(&z_loapic_regs, CONFIG_LOAPIC_BASE_ADDRESS, 0x1000,
92 K_MEM_CACHE_NONE);
93#endif /* DEVICE_MMIO_IS_IN_RAM */
Zide Chend27f6cb2020-02-10 14:09:05 -080094#ifndef CONFIG_X2APIC
95 /*
96 * in xAPIC and flat model, bits 24-31 in LDR (Logical APIC ID) are
97 * bitmap of target logical APIC ID and it supports maximum 8 local
98 * APICs.
99 *
100 * The logical APIC ID could be arbitrarily selected by system software
101 * and is different from local APIC ID in local APIC ID register.
102 *
103 * We choose 0 for BSP, and the index to x86_cpuboot[] for secondary
104 * CPUs.
105 *
106 * in X2APIC, LDR is read-only.
107 */
108 x86_write_xapic(LOAPIC_LDR, 1 << (cpu_number + 24));
109#endif
110
Charles E. Youse9a1e9272019-06-07 16:26:44 -0700111 /*
112 * enable the local APIC. note that we use xAPIC mode here, since
113 * x2APIC access is not enabled until the next step (if at all).
114 */
115
116 x86_write_xapic(LOAPIC_SVR,
117 x86_read_xapic(LOAPIC_SVR) | LOAPIC_ENABLE);
118
119#ifdef CONFIG_X2APIC
120 /*
121 * turn on x2APIC mode. we trust the config option, so
122 * we don't check CPUID to see if x2APIC is supported.
123 */
124
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500125 uint64_t msr = z_x86_msr_read(X86_APIC_BASE_MSR);
Charles E. Youse9a1e9272019-06-07 16:26:44 -0700126 msr |= X86_APIC_BASE_MSR_X2APIC;
127 z_x86_msr_write(X86_APIC_BASE_MSR, msr);
128#endif
129
Charles E. Youseaaecce42019-06-06 14:36:44 -0700130 loApicMaxLvt = (x86_read_loapic(LOAPIC_VER) & LOAPIC_MAXLVT_MASK) >> 16;
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700131
132 /* reset the DFR, TPR, TIMER_CONFIG, and TIMER_ICR */
133
Charles E. Youse0fe4e1b2019-06-05 10:28:38 -0700134#ifndef CONFIG_X2APIC
Zide Chend27f6cb2020-02-10 14:09:05 -0800135 /* Flat model */
Charles E. Youseaaecce42019-06-06 14:36:44 -0700136 x86_write_loapic(LOAPIC_DFR, 0xffffffff); /* no DFR in x2APIC mode */
Gustavo Lima Chaves9bb07ff2017-10-11 14:17:12 -0700137#endif
Gustavo Lima Chaves1a8e72c2017-10-11 14:08:17 -0700138
Charles E. Youseaaecce42019-06-06 14:36:44 -0700139 x86_write_loapic(LOAPIC_TPR, 0x0);
140 x86_write_loapic(LOAPIC_TIMER_CONFIG, 0x0);
141 x86_write_loapic(LOAPIC_TIMER_ICR, 0x0);
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700142
143 /* program Local Vector Table for the Virtual Wire Mode */
144
Gustavo Lima Chaves97a87162017-10-11 14:13:00 -0700145 /* skip LINT0/LINT1 for Jailhouse guest case, because we won't
146 * ever be waiting for interrupts on those
147 */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700148 /* set LINT0: extInt, high-polarity, edge-trigger, not-masked */
149
Charles E. Youseaaecce42019-06-06 14:36:44 -0700150 x86_write_loapic(LOAPIC_LINT0, (x86_read_loapic(LOAPIC_LINT0) &
Gustavo Lima Chaves1a8e72c2017-10-11 14:08:17 -0700151 ~(LOAPIC_MODE | LOAPIC_LOW |
152 LOAPIC_LEVEL | LOAPIC_LVT_MASKED)) |
153 (LOAPIC_EXT | LOAPIC_HIGH | LOAPIC_EDGE));
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700154
155 /* set LINT1: NMI, high-polarity, edge-trigger, not-masked */
156
Charles E. Youseaaecce42019-06-06 14:36:44 -0700157 x86_write_loapic(LOAPIC_LINT1, (x86_read_loapic(LOAPIC_LINT1) &
Gustavo Lima Chaves1a8e72c2017-10-11 14:08:17 -0700158 ~(LOAPIC_MODE | LOAPIC_LOW |
159 LOAPIC_LEVEL | LOAPIC_LVT_MASKED)) |
160 (LOAPIC_NMI | LOAPIC_HIGH | LOAPIC_EDGE));
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700161
162 /* lock the Local APIC interrupts */
163
Charles E. Youseaaecce42019-06-06 14:36:44 -0700164 x86_write_loapic(LOAPIC_TIMER, LOAPIC_LVT_MASKED);
165 x86_write_loapic(LOAPIC_ERROR, LOAPIC_LVT_MASKED);
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700166
Anas Nashif4c322582019-06-04 10:52:23 -0400167 if (loApicMaxLvt >= LOAPIC_LVT_P6) {
Charles E. Youseaaecce42019-06-06 14:36:44 -0700168 x86_write_loapic(LOAPIC_PMC, LOAPIC_LVT_MASKED);
Anas Nashif4c322582019-06-04 10:52:23 -0400169 }
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700170
Anas Nashif4c322582019-06-04 10:52:23 -0400171 if (loApicMaxLvt >= LOAPIC_LVT_PENTIUM4) {
Charles E. Youseaaecce42019-06-06 14:36:44 -0700172 x86_write_loapic(LOAPIC_THERMAL, LOAPIC_LVT_MASKED);
Anas Nashif4c322582019-06-04 10:52:23 -0400173 }
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700174
Andrew Boiec25d6c52015-12-09 14:53:41 -0800175#if CONFIG_LOAPIC_SPURIOUS_VECTOR
Charles E. Youseaaecce42019-06-06 14:36:44 -0700176 x86_write_loapic(LOAPIC_SVR, (x86_read_loapic(LOAPIC_SVR) & 0xFFFFFF00) |
Gustavo Lima Chaves1a8e72c2017-10-11 14:08:17 -0700177 (LOAPIC_SPURIOUS_VECTOR_ID & 0xFF));
Andrew Boiec25d6c52015-12-09 14:53:41 -0800178#endif
179
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700180 /* discard a pending interrupt if any */
Charles E. Youseaaecce42019-06-06 14:36:44 -0700181 x86_write_loapic(LOAPIC_EOI, 0);
Charles E. Yousea981f512019-09-28 16:58:22 -0400182}
Andrew Boiee98ac232016-08-02 12:05:08 -0700183
Charles E. Yousea981f512019-09-28 16:58:22 -0400184/**
185 *
186 * @brief Dummy initialization function.
187 *
188 * The local APIC is initialized via z_loapic_enable() long before the
189 * kernel runs through its device initializations, so this is unneeded.
190 */
Daniel Leunge4987482021-03-17 13:47:56 -0700191__boot_func
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200192static int loapic_init(const struct device *unused)
Charles E. Yousea981f512019-09-28 16:58:22 -0400193{
194 ARG_UNUSED(unused);
Dirk Brandewiebe1b1a42015-09-15 09:17:38 -0700195 return 0;
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700196}
197
Tomasz Bursztyka915f4ac2021-03-09 19:54:42 +0100198
Daniel Leunge4987482021-03-17 13:47:56 -0700199__pinned_func
Tomasz Bursztyka915f4ac2021-03-09 19:54:42 +0100200uint32_t z_loapic_irq_base(void)
201{
202 return z_ioapic_num_rtes();
203}
204
Anas Nashifea0d0b22015-07-01 17:22:39 -0400205/**
206 *
Anas Nashiff367f072015-07-01 17:51:40 -0400207 * @brief Set the vector field in the specified RTE
Anas Nashifea0d0b22015-07-01 17:22:39 -0400208 *
Andrew Boie325cae52016-09-22 11:20:26 -0700209 * This associates an IRQ with the desired vector in the IDT.
Anas Nashifea0d0b22015-07-01 17:22:39 -0400210 *
Anas Nashif1362e3c2015-07-01 17:29:04 -0400211 * @return N/A
Anas Nashifea0d0b22015-07-01 17:22:39 -0400212 */
Daniel Leunge4987482021-03-17 13:47:56 -0700213__boot_func
Patrik Flykt4344e272019-03-08 14:19:05 -0700214void z_loapic_int_vec_set(unsigned int irq, /* IRQ number of the interrupt */
Peter Mitsis2a4a6cf2015-07-27 11:02:41 -0400215 unsigned int vector /* vector to copy into the LVT */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700216 )
217{
Flavio Ceolin0866d182018-08-14 17:57:08 -0700218 unsigned int oldLevel; /* previous interrupt lock level */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700219
220 /*
221 * The following mappings are used:
222 *
223 * IRQ0 -> LOAPIC_TIMER
224 * IRQ1 -> LOAPIC_THERMAL
225 * IRQ2 -> LOAPIC_PMC
226 * IRQ3 -> LOAPIC_LINT0
227 * IRQ4 -> LOAPIC_LINT1
228 * IRQ5 -> LOAPIC_ERROR
229 *
230 * It's assumed that LVTs are spaced by 0x10 bytes
231 */
232
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700233 /* update the 'vector' bits in the LVT */
234
235 oldLevel = irq_lock();
Charles E. Youseaaecce42019-06-06 14:36:44 -0700236 x86_write_loapic(LOAPIC_TIMER + (irq * 0x10),
237 (x86_read_loapic(LOAPIC_TIMER + (irq * 0x10)) &
Gustavo Lima Chaves1a8e72c2017-10-11 14:08:17 -0700238 ~LOAPIC_VECTOR) | vector);
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700239 irq_unlock(oldLevel);
240}
241
Anas Nashifea0d0b22015-07-01 17:22:39 -0400242/**
243 *
Anas Nashiff367f072015-07-01 17:51:40 -0400244 * @brief Enable an individual LOAPIC interrupt (IRQ)
Anas Nashifea0d0b22015-07-01 17:22:39 -0400245 *
Dan Kalowsky3a109b12015-10-20 09:42:33 -0700246 * @param irq the IRQ number of the interrupt
247 *
Anas Nashifea0d0b22015-07-01 17:22:39 -0400248 * This routine clears the interrupt mask bit in the LVT for the specified IRQ
249 *
Anas Nashif1362e3c2015-07-01 17:29:04 -0400250 * @return N/A
Anas Nashifea0d0b22015-07-01 17:22:39 -0400251 */
Daniel Leunge4987482021-03-17 13:47:56 -0700252__pinned_func
Patrik Flykt4344e272019-03-08 14:19:05 -0700253void z_loapic_irq_enable(unsigned int irq)
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700254{
Flavio Ceolin0866d182018-08-14 17:57:08 -0700255 unsigned int oldLevel; /* previous interrupt lock level */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700256
257 /*
258 * See the comments in _LoApicLvtVecSet() regarding IRQ to LVT mappings
259 * and ths assumption concerning LVT spacing.
260 */
261
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700262 /* clear the mask bit in the LVT */
263
264 oldLevel = irq_lock();
Charles E. Youseaaecce42019-06-06 14:36:44 -0700265 x86_write_loapic(LOAPIC_TIMER + (irq * 0x10),
266 x86_read_loapic(LOAPIC_TIMER + (irq * 0x10)) &
Gustavo Lima Chaves1a8e72c2017-10-11 14:08:17 -0700267 ~LOAPIC_LVT_MASKED);
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700268 irq_unlock(oldLevel);
269}
270
Anas Nashifea0d0b22015-07-01 17:22:39 -0400271/**
272 *
Anas Nashiff367f072015-07-01 17:51:40 -0400273 * @brief Disable an individual LOAPIC interrupt (IRQ)
Anas Nashifea0d0b22015-07-01 17:22:39 -0400274 *
Dan Kalowsky3a109b12015-10-20 09:42:33 -0700275 * @param irq the IRQ number of the interrupt
276 *
Anas Nashifea0d0b22015-07-01 17:22:39 -0400277 * This routine clears the interrupt mask bit in the LVT for the specified IRQ
278 *
Anas Nashif1362e3c2015-07-01 17:29:04 -0400279 * @return N/A
Anas Nashifea0d0b22015-07-01 17:22:39 -0400280 */
Daniel Leunge4987482021-03-17 13:47:56 -0700281__pinned_func
Patrik Flykt4344e272019-03-08 14:19:05 -0700282void z_loapic_irq_disable(unsigned int irq)
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700283{
Flavio Ceolin0866d182018-08-14 17:57:08 -0700284 unsigned int oldLevel; /* previous interrupt lock level */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700285
286 /*
287 * See the comments in _LoApicLvtVecSet() regarding IRQ to LVT mappings
288 * and ths assumption concerning LVT spacing.
289 */
290
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700291 /* set the mask bit in the LVT */
292
293 oldLevel = irq_lock();
Charles E. Youseaaecce42019-06-06 14:36:44 -0700294 x86_write_loapic(LOAPIC_TIMER + (irq * 0x10),
295 x86_read_loapic(LOAPIC_TIMER + (irq * 0x10)) |
Gustavo Lima Chaves1a8e72c2017-10-11 14:08:17 -0700296 LOAPIC_LVT_MASKED);
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700297 irq_unlock(oldLevel);
298}
Yonattan Louised2108bf2015-08-21 19:10:32 -0500299
300
301/**
302 * @brief Find the currently executing interrupt vector, if any
303 *
304 * This routine finds the vector of the interrupt that is being processed.
305 * The ISR (In-Service Register) register contain the vectors of the interrupts
David B. Kinder896cf7a2017-04-19 10:45:34 -0700306 * in service. And the higher vector is the identification of the interrupt
Yonattan Louised2108bf2015-08-21 19:10:32 -0500307 * being currently processed.
308 *
Andrew Boiea69ea782016-07-12 11:42:18 -0700309 * This function must be called with interrupts locked in interrupt context.
310 *
Yonattan Louised2108bf2015-08-21 19:10:32 -0500311 * ISR registers' offsets:
312 * --------------------
313 * | Offset | bits |
314 * --------------------
315 * | 0100H | 0:31 |
316 * | 0110H | 32:63 |
317 * | 0120H | 64:95 |
318 * | 0130H | 96:127 |
319 * | 0140H | 128:159 |
320 * | 0150H | 160:191 |
321 * | 0160H | 192:223 |
322 * | 0170H | 224:255 |
323 * --------------------
324 *
Andrew Boieeec13ca2016-09-08 11:01:23 -0700325 * @return The vector of the interrupt that is currently being processed, or -1
326 * if no IRQ is being serviced.
Yonattan Louised2108bf2015-08-21 19:10:32 -0500327 */
Daniel Leunge4987482021-03-17 13:47:56 -0700328__pinned_func
Charles E. Youse0325a3d2019-06-28 13:06:37 -0700329int z_irq_controller_isr_vector_get(void)
Yonattan Louised2108bf2015-08-21 19:10:32 -0500330{
Andrew Boiea69ea782016-07-12 11:42:18 -0700331 int pReg, block;
Yonattan Louised2108bf2015-08-21 19:10:32 -0500332
Andrew Boieeec13ca2016-09-08 11:01:23 -0700333 /* Block 0 bits never lit up as these are all exception or reserved
334 * vectors
335 */
336 for (block = 7; likely(block > 0); block--) {
Charles E. Youseaaecce42019-06-06 14:36:44 -0700337 pReg = x86_read_loapic(LOAPIC_ISR + (block * 0x10));
Andrew Boiea69ea782016-07-12 11:42:18 -0700338 if (pReg) {
339 return (block * 32) + (find_msb_set(pReg) - 1);
Yonattan Louised2108bf2015-08-21 19:10:32 -0500340 }
Yonattan Louised2108bf2015-08-21 19:10:32 -0500341
Andrew Boiea69ea782016-07-12 11:42:18 -0700342 }
Andrew Boieeec13ca2016-09-08 11:01:23 -0700343 return -1;
Yonattan Louised2108bf2015-08-21 19:10:32 -0500344}
Daniel Leung921ee032015-12-08 11:17:56 -0800345
Anas Nashifdd931f92020-09-01 18:31:40 -0400346#ifdef CONFIG_PM_DEVICE
Daniel Leunge4987482021-03-17 13:47:56 -0700347__pinned_func
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200348static int loapic_suspend(const struct device *port)
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700349{
Kumar Galaa1b77fd2020-05-27 11:26:57 -0500350 volatile uint32_t lvt; /* local vector table entry value */
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700351 int loapic_irq;
352
353 ARG_UNUSED(port);
354
Flavio Ceolinda49f2e2018-09-11 19:09:03 -0700355 (void)memset(loapic_suspend_buf, 0, (LOPIC_SUSPEND_BITS_REQD >> 3));
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700356
357 for (loapic_irq = 0; loapic_irq < LOAPIC_IRQ_COUNT; loapic_irq++) {
358
Tomasz Bursztyka915f4ac2021-03-09 19:54:42 +0100359 if (_irq_to_interrupt_vector[z_loapic_irq_base() + loapic_irq]) {
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700360
361 /* Since vector numbers are already present in RAM/ROM,
362 * We save only the mask bits here.
363 */
Charles E. Youseaaecce42019-06-06 14:36:44 -0700364 lvt = x86_read_loapic(LOAPIC_TIMER + (loapic_irq * 0x10));
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700365
Patrik Flykt24d71432019-03-26 19:57:45 -0600366 if ((lvt & LOAPIC_LVT_MASKED) == 0U) {
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700367 sys_bitfield_set_bit((mem_addr_t)loapic_suspend_buf,
368 loapic_irq);
369 }
370 }
371 }
Gerard Marull-Paretasc2cf1ad2021-06-04 17:41:39 +0200372
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700373 return 0;
374}
375
Daniel Leunge4987482021-03-17 13:47:56 -0700376__pinned_func
Tomasz Bursztykae18fcbb2020-04-30 20:33:38 +0200377int loapic_resume(const struct device *port)
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700378{
379 int loapic_irq;
380
381 ARG_UNUSED(port);
382
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700383 /* Assuming all loapic device registers lose their state, the call to
Patrik Flykt97b3bd12019-03-12 15:15:42 -0600384 * z_loapic_init(), should bring all the registers to a sane state.
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700385 */
Patrik Flykt97b3bd12019-03-12 15:15:42 -0600386 loapic_init(NULL);
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700387
388 for (loapic_irq = 0; loapic_irq < LOAPIC_IRQ_COUNT; loapic_irq++) {
389
Tomasz Bursztyka915f4ac2021-03-09 19:54:42 +0100390 if (_irq_to_interrupt_vector[z_loapic_irq_base() + loapic_irq]) {
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700391 /* Configure vector and enable the required ones*/
Patrik Flykt4344e272019-03-08 14:19:05 -0700392 z_loapic_int_vec_set(loapic_irq,
Tomasz Bursztyka915f4ac2021-03-09 19:54:42 +0100393 _irq_to_interrupt_vector[z_loapic_irq_base() +
394 loapic_irq]);
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700395
396 if (sys_bitfield_test_bit((mem_addr_t) loapic_suspend_buf,
397 loapic_irq)) {
Patrik Flykt4344e272019-03-08 14:19:05 -0700398 z_loapic_irq_enable(loapic_irq);
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700399 }
400 }
401 }
402
403 return 0;
404}
405
amirkaplc4902192016-09-11 19:17:19 +0300406/*
407* Implements the driver control management functionality
408* the *context may include IN data or/and OUT data
409*/
Daniel Leunge4987482021-03-17 13:47:56 -0700410__pinned_func
Gerard Marull-Paretas495672a2021-07-05 10:35:15 +0200411static int loapic_device_ctrl(const struct device *dev,
Gerard Marull-Paretas7ccc1a42021-07-05 15:13:40 +0200412 enum pm_device_action action)
amirkaplc4902192016-09-11 19:17:19 +0300413{
Ramakrishna Pallalae1639b52019-02-14 09:35:42 +0530414 int ret = 0;
415
Gerard Marull-Paretas7ccc1a42021-07-05 15:13:40 +0200416 switch (action) {
417 case PM_DEVICE_ACTION_SUSPEND:
Gerard Marull-Paretas495672a2021-07-05 10:35:15 +0200418 ret = loapic_suspend(dev);
419 break;
Gerard Marull-Paretas7ccc1a42021-07-05 15:13:40 +0200420 case PM_DEVICE_ACTION_RESUME:
Gerard Marull-Paretas495672a2021-07-05 10:35:15 +0200421 ret = loapic_resume(dev);
422 break;
423 default:
424 return -ENOTSUP;
amirkaplc4902192016-09-11 19:17:19 +0300425 }
426
Ramakrishna Pallalae1639b52019-02-14 09:35:42 +0530427 return ret;
amirkaplc4902192016-09-11 19:17:19 +0300428}
429
Patrik Flykt97b3bd12019-03-12 15:15:42 -0600430SYS_DEVICE_DEFINE("loapic", loapic_init, loapic_device_ctrl, PRE_KERNEL_1,
amirkaplc4902192016-09-11 19:17:19 +0300431 CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700432#else
Patrik Flykt97b3bd12019-03-12 15:15:42 -0600433SYS_INIT(loapic_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
Anas Nashifdd931f92020-09-01 18:31:40 -0400434#endif /* CONFIG_PM_DEVICE */
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700435
Andrew Boiec25d6c52015-12-09 14:53:41 -0800436
437#if CONFIG_LOAPIC_SPURIOUS_VECTOR
Patrik Flykt97b3bd12019-03-12 15:15:42 -0600438extern void z_loapic_spurious_handler(void);
Andrew Boiec25d6c52015-12-09 14:53:41 -0800439
Patrik Flykt97b3bd12019-03-12 15:15:42 -0600440NANO_CPU_INT_REGISTER(z_loapic_spurious_handler, NANO_SOFT_IRQ,
Andrew Boiec25d6c52015-12-09 14:53:41 -0800441 LOAPIC_SPURIOUS_VECTOR_ID >> 4,
442 LOAPIC_SPURIOUS_VECTOR_ID, 0);
443#endif