blob: c534ddec6a66892afed1714a0bb5b88733c0d3c7 [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 */
Daniel Leung921ee032015-12-08 11:17:56 -080021#include <init.h>
Anas Nashif43a49332019-06-21 12:54:15 -040022#include <drivers/interrupt_controller/sysapic.h>
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070023
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070024/* Local APIC Version Register Bits */
25
26#define LOAPIC_VERSION_MASK 0x000000ff /* LO APIC Version mask */
27#define LOAPIC_MAXLVT_MASK 0x00ff0000 /* LO APIC Max LVT mask */
28#define LOAPIC_PENTIUM4 0x00000014 /* LO APIC in Pentium4 */
29#define LOAPIC_LVT_PENTIUM4 5 /* LO APIC LVT - Pentium4 */
30#define LOAPIC_LVT_P6 4 /* LO APIC LVT - P6 */
31#define LOAPIC_LVT_P5 3 /* LO APIC LVT - P5 */
32
33/* Local APIC Vector Table Bits */
34
35#define LOAPIC_VECTOR 0x000000ff /* vectorNo */
36#define LOAPIC_MODE 0x00000700 /* delivery mode */
37#define LOAPIC_FIXED 0x00000000 /* delivery mode: FIXED */
38#define LOAPIC_SMI 0x00000200 /* delivery mode: SMI */
39#define LOAPIC_NMI 0x00000400 /* delivery mode: NMI */
40#define LOAPIC_EXT 0x00000700 /* delivery mode: ExtINT */
41#define LOAPIC_IDLE 0x00000000 /* delivery status: Idle */
42#define LOAPIC_PEND 0x00001000 /* delivery status: Pend */
43#define LOAPIC_HIGH 0x00000000 /* polarity: High */
44#define LOAPIC_LOW 0x00002000 /* polarity: Low */
45#define LOAPIC_REMOTE 0x00004000 /* remote IRR */
46#define LOAPIC_EDGE 0x00000000 /* trigger mode: Edge */
47#define LOAPIC_LEVEL 0x00008000 /* trigger mode: Level */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070048
49/* Local APIC Spurious-Interrupt Register Bits */
50
51#define LOAPIC_ENABLE 0x100 /* APIC Enabled */
52#define LOAPIC_FOCUS_DISABLE 0x200 /* Focus Processor Checking */
53
Andrew Boiec25d6c52015-12-09 14:53:41 -080054#if CONFIG_LOAPIC_SPURIOUS_VECTOR_ID == -1
55#define LOAPIC_SPURIOUS_VECTOR_ID (CONFIG_IDT_NUM_VECTORS - 1)
56#else
57#define LOAPIC_SPURIOUS_VECTOR_ID CONFIG_LOAPIC_SPURIOUS_VECTOR_ID
58#endif
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070059
Jithu Joseph09a0c2f2016-05-06 21:55:51 -070060#define LOPIC_SSPND_BITS_PER_IRQ 1 /* Just the one for enable disable*/
61#define LOPIC_SUSPEND_BITS_REQD (ROUND_UP((LOAPIC_IRQ_COUNT * LOPIC_SSPND_BITS_PER_IRQ), 32))
62#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
Anas Nashif190e3682019-06-25 12:26:13 -040063#include <power/power.h>
Kumar Galaccad5bf2017-04-21 10:03:20 -050064u32_t loapic_suspend_buf[LOPIC_SUSPEND_BITS_REQD / 32] = {0};
65static u32_t loapic_device_power_state = DEVICE_PM_ACTIVE_STATE;
Jithu Joseph09a0c2f2016-05-06 21:55:51 -070066#endif
67
Charles E. Yousee9f6cb22019-06-07 15:17:13 -070068/*
69 * this should not be a function at all, really, it should be
70 * hand-coded in include/drivers/sysapic.h. but for now it remains
71 * a function, just moved here from drivers/timer/loapic_timer.c
72 * where it REALLY didn't belong.
73 */
74
75#ifdef CONFIG_X2APIC
76void z_x2apic_eoi(void)
77{
78 x86_write_x2apic(LOAPIC_EOI, 0);
79}
80#endif
81
Anas Nashifea0d0b22015-07-01 17:22:39 -040082/**
83 *
Anas Nashiff367f072015-07-01 17:51:40 -040084 * @brief Initialize the Local APIC or xAPIC
Anas Nashifea0d0b22015-07-01 17:22:39 -040085 *
86 * This routine initializes Local APIC or xAPIC.
87 *
Anas Nashif1362e3c2015-07-01 17:29:04 -040088 * @return N/A
Anas Nashifea0d0b22015-07-01 17:22:39 -040089 *
90 */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070091
Patrik Flykt97b3bd12019-03-12 15:15:42 -060092static int loapic_init(struct device *unused)
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070093{
Dirk Brandewiebe1b1a42015-09-15 09:17:38 -070094 ARG_UNUSED(unused);
Kumar Galaccad5bf2017-04-21 10:03:20 -050095 s32_t loApicMaxLvt; /* local APIC Max LVT */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -070096
Charles E. Youse9a1e9272019-06-07 16:26:44 -070097 /*
98 * enable the local APIC. note that we use xAPIC mode here, since
99 * x2APIC access is not enabled until the next step (if at all).
100 */
101
102 x86_write_xapic(LOAPIC_SVR,
103 x86_read_xapic(LOAPIC_SVR) | LOAPIC_ENABLE);
104
105#ifdef CONFIG_X2APIC
106 /*
107 * turn on x2APIC mode. we trust the config option, so
108 * we don't check CPUID to see if x2APIC is supported.
109 */
110
111 u64_t msr = z_x86_msr_read(X86_APIC_BASE_MSR);
112 msr |= X86_APIC_BASE_MSR_X2APIC;
113 z_x86_msr_write(X86_APIC_BASE_MSR, msr);
114#endif
115
Charles E. Youseaaecce42019-06-06 14:36:44 -0700116 loApicMaxLvt = (x86_read_loapic(LOAPIC_VER) & LOAPIC_MAXLVT_MASK) >> 16;
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700117
118 /* reset the DFR, TPR, TIMER_CONFIG, and TIMER_ICR */
119
Charles E. Youse0fe4e1b2019-06-05 10:28:38 -0700120#ifndef CONFIG_X2APIC
Charles E. Youseaaecce42019-06-06 14:36:44 -0700121 x86_write_loapic(LOAPIC_DFR, 0xffffffff); /* no DFR in x2APIC mode */
Gustavo Lima Chaves9bb07ff2017-10-11 14:17:12 -0700122#endif
Gustavo Lima Chaves1a8e72c2017-10-11 14:08:17 -0700123
Charles E. Youseaaecce42019-06-06 14:36:44 -0700124 x86_write_loapic(LOAPIC_TPR, 0x0);
125 x86_write_loapic(LOAPIC_TIMER_CONFIG, 0x0);
126 x86_write_loapic(LOAPIC_TIMER_ICR, 0x0);
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700127
128 /* program Local Vector Table for the Virtual Wire Mode */
129
Gustavo Lima Chaves97a87162017-10-11 14:13:00 -0700130 /* skip LINT0/LINT1 for Jailhouse guest case, because we won't
131 * ever be waiting for interrupts on those
132 */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700133 /* set LINT0: extInt, high-polarity, edge-trigger, not-masked */
134
Charles E. Youseaaecce42019-06-06 14:36:44 -0700135 x86_write_loapic(LOAPIC_LINT0, (x86_read_loapic(LOAPIC_LINT0) &
Gustavo Lima Chaves1a8e72c2017-10-11 14:08:17 -0700136 ~(LOAPIC_MODE | LOAPIC_LOW |
137 LOAPIC_LEVEL | LOAPIC_LVT_MASKED)) |
138 (LOAPIC_EXT | LOAPIC_HIGH | LOAPIC_EDGE));
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700139
140 /* set LINT1: NMI, high-polarity, edge-trigger, not-masked */
141
Charles E. Youseaaecce42019-06-06 14:36:44 -0700142 x86_write_loapic(LOAPIC_LINT1, (x86_read_loapic(LOAPIC_LINT1) &
Gustavo Lima Chaves1a8e72c2017-10-11 14:08:17 -0700143 ~(LOAPIC_MODE | LOAPIC_LOW |
144 LOAPIC_LEVEL | LOAPIC_LVT_MASKED)) |
145 (LOAPIC_NMI | LOAPIC_HIGH | LOAPIC_EDGE));
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700146
147 /* lock the Local APIC interrupts */
148
Charles E. Youseaaecce42019-06-06 14:36:44 -0700149 x86_write_loapic(LOAPIC_TIMER, LOAPIC_LVT_MASKED);
150 x86_write_loapic(LOAPIC_ERROR, LOAPIC_LVT_MASKED);
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700151
Anas Nashif4c322582019-06-04 10:52:23 -0400152 if (loApicMaxLvt >= LOAPIC_LVT_P6) {
Charles E. Youseaaecce42019-06-06 14:36:44 -0700153 x86_write_loapic(LOAPIC_PMC, LOAPIC_LVT_MASKED);
Anas Nashif4c322582019-06-04 10:52:23 -0400154 }
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700155
Anas Nashif4c322582019-06-04 10:52:23 -0400156 if (loApicMaxLvt >= LOAPIC_LVT_PENTIUM4) {
Charles E. Youseaaecce42019-06-06 14:36:44 -0700157 x86_write_loapic(LOAPIC_THERMAL, LOAPIC_LVT_MASKED);
Anas Nashif4c322582019-06-04 10:52:23 -0400158 }
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700159
Andrew Boiec25d6c52015-12-09 14:53:41 -0800160#if CONFIG_LOAPIC_SPURIOUS_VECTOR
Charles E. Youseaaecce42019-06-06 14:36:44 -0700161 x86_write_loapic(LOAPIC_SVR, (x86_read_loapic(LOAPIC_SVR) & 0xFFFFFF00) |
Gustavo Lima Chaves1a8e72c2017-10-11 14:08:17 -0700162 (LOAPIC_SPURIOUS_VECTOR_ID & 0xFF));
Andrew Boiec25d6c52015-12-09 14:53:41 -0800163#endif
164
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700165 /* discard a pending interrupt if any */
Andrew Boiee98ac232016-08-02 12:05:08 -0700166#if CONFIG_EOI_FORWARDING_BUG
Patrik Flykt4344e272019-03-08 14:19:05 -0700167 z_lakemont_eoi();
Andrew Boiee98ac232016-08-02 12:05:08 -0700168#else
Charles E. Youseaaecce42019-06-06 14:36:44 -0700169 x86_write_loapic(LOAPIC_EOI, 0);
Andrew Boiee98ac232016-08-02 12:05:08 -0700170#endif
171
Dirk Brandewiebe1b1a42015-09-15 09:17:38 -0700172 return 0;
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700173}
174
Anas Nashifea0d0b22015-07-01 17:22:39 -0400175/**
176 *
Anas Nashiff367f072015-07-01 17:51:40 -0400177 * @brief Set the vector field in the specified RTE
Anas Nashifea0d0b22015-07-01 17:22:39 -0400178 *
Andrew Boie325cae52016-09-22 11:20:26 -0700179 * This associates an IRQ with the desired vector in the IDT.
Anas Nashifea0d0b22015-07-01 17:22:39 -0400180 *
Anas Nashif1362e3c2015-07-01 17:29:04 -0400181 * @return N/A
Anas Nashifea0d0b22015-07-01 17:22:39 -0400182 */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700183
Patrik Flykt4344e272019-03-08 14:19:05 -0700184void z_loapic_int_vec_set(unsigned int irq, /* IRQ number of the interrupt */
Peter Mitsis2a4a6cf2015-07-27 11:02:41 -0400185 unsigned int vector /* vector to copy into the LVT */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700186 )
187{
Flavio Ceolin0866d182018-08-14 17:57:08 -0700188 unsigned int oldLevel; /* previous interrupt lock level */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700189
190 /*
191 * The following mappings are used:
192 *
193 * IRQ0 -> LOAPIC_TIMER
194 * IRQ1 -> LOAPIC_THERMAL
195 * IRQ2 -> LOAPIC_PMC
196 * IRQ3 -> LOAPIC_LINT0
197 * IRQ4 -> LOAPIC_LINT1
198 * IRQ5 -> LOAPIC_ERROR
199 *
200 * It's assumed that LVTs are spaced by 0x10 bytes
201 */
202
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700203 /* update the 'vector' bits in the LVT */
204
205 oldLevel = irq_lock();
Charles E. Youseaaecce42019-06-06 14:36:44 -0700206 x86_write_loapic(LOAPIC_TIMER + (irq * 0x10),
207 (x86_read_loapic(LOAPIC_TIMER + (irq * 0x10)) &
Gustavo Lima Chaves1a8e72c2017-10-11 14:08:17 -0700208 ~LOAPIC_VECTOR) | vector);
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700209 irq_unlock(oldLevel);
210}
211
Anas Nashifea0d0b22015-07-01 17:22:39 -0400212/**
213 *
Anas Nashiff367f072015-07-01 17:51:40 -0400214 * @brief Enable an individual LOAPIC interrupt (IRQ)
Anas Nashifea0d0b22015-07-01 17:22:39 -0400215 *
Dan Kalowsky3a109b12015-10-20 09:42:33 -0700216 * @param irq the IRQ number of the interrupt
217 *
Anas Nashifea0d0b22015-07-01 17:22:39 -0400218 * This routine clears the interrupt mask bit in the LVT for the specified IRQ
219 *
Anas Nashif1362e3c2015-07-01 17:29:04 -0400220 * @return N/A
Anas Nashifea0d0b22015-07-01 17:22:39 -0400221 */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700222
Patrik Flykt4344e272019-03-08 14:19:05 -0700223void z_loapic_irq_enable(unsigned int irq)
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700224{
Flavio Ceolin0866d182018-08-14 17:57:08 -0700225 unsigned int oldLevel; /* previous interrupt lock level */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700226
227 /*
228 * See the comments in _LoApicLvtVecSet() regarding IRQ to LVT mappings
229 * and ths assumption concerning LVT spacing.
230 */
231
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700232 /* clear the mask bit in the LVT */
233
234 oldLevel = irq_lock();
Charles E. Youseaaecce42019-06-06 14:36:44 -0700235 x86_write_loapic(LOAPIC_TIMER + (irq * 0x10),
236 x86_read_loapic(LOAPIC_TIMER + (irq * 0x10)) &
Gustavo Lima Chaves1a8e72c2017-10-11 14:08:17 -0700237 ~LOAPIC_LVT_MASKED);
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700238 irq_unlock(oldLevel);
239}
240
Anas Nashifea0d0b22015-07-01 17:22:39 -0400241/**
242 *
Anas Nashiff367f072015-07-01 17:51:40 -0400243 * @brief Disable an individual LOAPIC interrupt (IRQ)
Anas Nashifea0d0b22015-07-01 17:22:39 -0400244 *
Dan Kalowsky3a109b12015-10-20 09:42:33 -0700245 * @param irq the IRQ number of the interrupt
246 *
Anas Nashifea0d0b22015-07-01 17:22:39 -0400247 * This routine clears the interrupt mask bit in the LVT for the specified IRQ
248 *
Anas Nashif1362e3c2015-07-01 17:29:04 -0400249 * @return N/A
Anas Nashifea0d0b22015-07-01 17:22:39 -0400250 */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700251
Patrik Flykt4344e272019-03-08 14:19:05 -0700252void z_loapic_irq_disable(unsigned int irq)
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700253{
Flavio Ceolin0866d182018-08-14 17:57:08 -0700254 unsigned int oldLevel; /* previous interrupt lock level */
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700255
256 /*
257 * See the comments in _LoApicLvtVecSet() regarding IRQ to LVT mappings
258 * and ths assumption concerning LVT spacing.
259 */
260
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700261 /* set the mask bit in the LVT */
262
263 oldLevel = irq_lock();
Charles E. Youseaaecce42019-06-06 14:36:44 -0700264 x86_write_loapic(LOAPIC_TIMER + (irq * 0x10),
265 x86_read_loapic(LOAPIC_TIMER + (irq * 0x10)) |
Gustavo Lima Chaves1a8e72c2017-10-11 14:08:17 -0700266 LOAPIC_LVT_MASKED);
Inaky Perez-Gonzalez8ddf82c2015-04-10 16:44:37 -0700267 irq_unlock(oldLevel);
268}
Yonattan Louised2108bf2015-08-21 19:10:32 -0500269
270
271/**
272 * @brief Find the currently executing interrupt vector, if any
273 *
274 * This routine finds the vector of the interrupt that is being processed.
275 * The ISR (In-Service Register) register contain the vectors of the interrupts
David B. Kinder896cf7a2017-04-19 10:45:34 -0700276 * in service. And the higher vector is the identification of the interrupt
Yonattan Louised2108bf2015-08-21 19:10:32 -0500277 * being currently processed.
278 *
Andrew Boiea69ea782016-07-12 11:42:18 -0700279 * This function must be called with interrupts locked in interrupt context.
280 *
Yonattan Louised2108bf2015-08-21 19:10:32 -0500281 * ISR registers' offsets:
282 * --------------------
283 * | Offset | bits |
284 * --------------------
285 * | 0100H | 0:31 |
286 * | 0110H | 32:63 |
287 * | 0120H | 64:95 |
288 * | 0130H | 96:127 |
289 * | 0140H | 128:159 |
290 * | 0150H | 160:191 |
291 * | 0160H | 192:223 |
292 * | 0170H | 224:255 |
293 * --------------------
294 *
Andrew Boieeec13ca2016-09-08 11:01:23 -0700295 * @return The vector of the interrupt that is currently being processed, or -1
296 * if no IRQ is being serviced.
Yonattan Louised2108bf2015-08-21 19:10:32 -0500297 */
Charles E. Youse0325a3d2019-06-28 13:06:37 -0700298int z_irq_controller_isr_vector_get(void)
Yonattan Louised2108bf2015-08-21 19:10:32 -0500299{
Andrew Boiea69ea782016-07-12 11:42:18 -0700300 int pReg, block;
Yonattan Louised2108bf2015-08-21 19:10:32 -0500301
Andrew Boieeec13ca2016-09-08 11:01:23 -0700302 /* Block 0 bits never lit up as these are all exception or reserved
303 * vectors
304 */
305 for (block = 7; likely(block > 0); block--) {
Charles E. Youseaaecce42019-06-06 14:36:44 -0700306 pReg = x86_read_loapic(LOAPIC_ISR + (block * 0x10));
Andrew Boiea69ea782016-07-12 11:42:18 -0700307 if (pReg) {
308 return (block * 32) + (find_msb_set(pReg) - 1);
Yonattan Louised2108bf2015-08-21 19:10:32 -0500309 }
Yonattan Louised2108bf2015-08-21 19:10:32 -0500310
Andrew Boiea69ea782016-07-12 11:42:18 -0700311 }
Andrew Boieeec13ca2016-09-08 11:01:23 -0700312 return -1;
Yonattan Louised2108bf2015-08-21 19:10:32 -0500313}
Daniel Leung921ee032015-12-08 11:17:56 -0800314
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700315#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
amirkaplc4902192016-09-11 19:17:19 +0300316static int loapic_suspend(struct device *port)
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700317{
Gustavo Lima Chaves1a8e72c2017-10-11 14:08:17 -0700318 volatile u32_t lvt; /* local vector table entry value */
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700319 int loapic_irq;
320
321 ARG_UNUSED(port);
322
Flavio Ceolinda49f2e2018-09-11 19:09:03 -0700323 (void)memset(loapic_suspend_buf, 0, (LOPIC_SUSPEND_BITS_REQD >> 3));
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700324
325 for (loapic_irq = 0; loapic_irq < LOAPIC_IRQ_COUNT; loapic_irq++) {
326
327 if (_irq_to_interrupt_vector[LOAPIC_IRQ_BASE + loapic_irq]) {
328
329 /* Since vector numbers are already present in RAM/ROM,
330 * We save only the mask bits here.
331 */
Charles E. Youseaaecce42019-06-06 14:36:44 -0700332 lvt = x86_read_loapic(LOAPIC_TIMER + (loapic_irq * 0x10));
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700333
Patrik Flykt24d71432019-03-26 19:57:45 -0600334 if ((lvt & LOAPIC_LVT_MASKED) == 0U) {
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700335 sys_bitfield_set_bit((mem_addr_t)loapic_suspend_buf,
336 loapic_irq);
337 }
338 }
339 }
amirkaplc4902192016-09-11 19:17:19 +0300340 loapic_device_power_state = DEVICE_PM_SUSPEND_STATE;
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700341 return 0;
342}
343
amirkaplc4902192016-09-11 19:17:19 +0300344int loapic_resume(struct device *port)
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700345{
346 int loapic_irq;
347
348 ARG_UNUSED(port);
349
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700350 /* Assuming all loapic device registers lose their state, the call to
Patrik Flykt97b3bd12019-03-12 15:15:42 -0600351 * z_loapic_init(), should bring all the registers to a sane state.
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700352 */
Patrik Flykt97b3bd12019-03-12 15:15:42 -0600353 loapic_init(NULL);
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700354
355 for (loapic_irq = 0; loapic_irq < LOAPIC_IRQ_COUNT; loapic_irq++) {
356
357 if (_irq_to_interrupt_vector[LOAPIC_IRQ_BASE + loapic_irq]) {
358 /* Configure vector and enable the required ones*/
Patrik Flykt4344e272019-03-08 14:19:05 -0700359 z_loapic_int_vec_set(loapic_irq,
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700360 _irq_to_interrupt_vector[LOAPIC_IRQ_BASE + loapic_irq]);
361
362 if (sys_bitfield_test_bit((mem_addr_t) loapic_suspend_buf,
363 loapic_irq)) {
Patrik Flykt4344e272019-03-08 14:19:05 -0700364 z_loapic_irq_enable(loapic_irq);
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700365 }
366 }
367 }
amirkaplc4902192016-09-11 19:17:19 +0300368 loapic_device_power_state = DEVICE_PM_ACTIVE_STATE;
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700369
370 return 0;
371}
372
amirkaplc4902192016-09-11 19:17:19 +0300373/*
374* Implements the driver control management functionality
375* the *context may include IN data or/and OUT data
376*/
Kumar Galaccad5bf2017-04-21 10:03:20 -0500377static int loapic_device_ctrl(struct device *port, u32_t ctrl_command,
Ramakrishna Pallalae1639b52019-02-14 09:35:42 +0530378 void *context, device_pm_cb cb, void *arg)
amirkaplc4902192016-09-11 19:17:19 +0300379{
Ramakrishna Pallalae1639b52019-02-14 09:35:42 +0530380 int ret = 0;
381
amirkaplc4902192016-09-11 19:17:19 +0300382 if (ctrl_command == DEVICE_PM_SET_POWER_STATE) {
Kumar Galaccad5bf2017-04-21 10:03:20 -0500383 if (*((u32_t *)context) == DEVICE_PM_SUSPEND_STATE) {
Ramakrishna Pallalae1639b52019-02-14 09:35:42 +0530384 ret = loapic_suspend(port);
Kumar Galaccad5bf2017-04-21 10:03:20 -0500385 } else if (*((u32_t *)context) == DEVICE_PM_ACTIVE_STATE) {
Ramakrishna Pallalae1639b52019-02-14 09:35:42 +0530386 ret = loapic_resume(port);
amirkaplc4902192016-09-11 19:17:19 +0300387 }
388 } else if (ctrl_command == DEVICE_PM_GET_POWER_STATE) {
Kumar Galaccad5bf2017-04-21 10:03:20 -0500389 *((u32_t *)context) = loapic_device_power_state;
amirkaplc4902192016-09-11 19:17:19 +0300390 }
391
Ramakrishna Pallalae1639b52019-02-14 09:35:42 +0530392 if (cb) {
393 cb(port, ret, context, arg);
394 }
395
396 return ret;
amirkaplc4902192016-09-11 19:17:19 +0300397}
398
Patrik Flykt97b3bd12019-03-12 15:15:42 -0600399SYS_DEVICE_DEFINE("loapic", loapic_init, loapic_device_ctrl, PRE_KERNEL_1,
amirkaplc4902192016-09-11 19:17:19 +0300400 CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700401#else
Patrik Flykt97b3bd12019-03-12 15:15:42 -0600402SYS_INIT(loapic_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
Jithu Joseph09a0c2f2016-05-06 21:55:51 -0700403#endif /* CONFIG_DEVICE_POWER_MANAGEMENT */
404
Andrew Boiec25d6c52015-12-09 14:53:41 -0800405
406#if CONFIG_LOAPIC_SPURIOUS_VECTOR
Patrik Flykt97b3bd12019-03-12 15:15:42 -0600407extern void z_loapic_spurious_handler(void);
Andrew Boiec25d6c52015-12-09 14:53:41 -0800408
Patrik Flykt97b3bd12019-03-12 15:15:42 -0600409NANO_CPU_INT_REGISTER(z_loapic_spurious_handler, NANO_SOFT_IRQ,
Andrew Boiec25d6c52015-12-09 14:53:41 -0800410 LOAPIC_SPURIOUS_VECTOR_ID >> 4,
411 LOAPIC_SPURIOUS_VECTOR_ID, 0);
412#endif