Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 1984-2008, 2011-2015 Wind River Systems, Inc. |
David B. Kinder | ac74d8b | 2017-01-18 17:01:01 -0800 | [diff] [blame] | 3 | * SPDX-License-Identifier: Apache-2.0 |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 4 | */ |
| 5 | |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 6 | /* |
| 7 | * driver for x86 CPU local APIC (as an interrupt controller) |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 8 | */ |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 9 | |
Flavio Santes | b04cdcd | 2016-12-04 14:59:37 -0600 | [diff] [blame] | 10 | #include <kernel.h> |
Gustavo Lima Chaves | 9bb07ff | 2017-10-11 14:17:12 -0700 | [diff] [blame] | 11 | #include <kernel_structs.h> |
Dan Kalowsky | c02dd34 | 2015-05-28 10:56:47 -0700 | [diff] [blame] | 12 | #include <arch/cpu.h> |
Kumar Gala | 7890816 | 2017-04-19 10:32:08 -0500 | [diff] [blame] | 13 | #include <zephyr/types.h> |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 14 | #include <string.h> |
Anas Nashif | 5eb90ec | 2019-06-26 10:33:39 -0400 | [diff] [blame] | 15 | #include <sys/__assert.h> |
Charles E. Youse | 9a1e927 | 2019-06-07 16:26:44 -0700 | [diff] [blame] | 16 | #include <arch/x86/msr.h> |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 17 | |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 18 | #include <toolchain.h> |
Anas Nashif | 397d29d | 2017-06-17 11:30:47 -0400 | [diff] [blame] | 19 | #include <linker/sections.h> |
Anas Nashif | 43a4933 | 2019-06-21 12:54:15 -0400 | [diff] [blame] | 20 | #include <drivers/interrupt_controller/loapic.h> /* public API declarations */ |
Daniel Leung | 921ee03 | 2015-12-08 11:17:56 -0800 | [diff] [blame] | 21 | #include <init.h> |
Anas Nashif | 43a4933 | 2019-06-21 12:54:15 -0400 | [diff] [blame] | 22 | #include <drivers/interrupt_controller/sysapic.h> |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 23 | |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 24 | /* 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-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 48 | |
| 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 Boie | c25d6c5 | 2015-12-09 14:53:41 -0800 | [diff] [blame] | 54 | #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-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 59 | |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 60 | #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 Nashif | 190e368 | 2019-06-25 12:26:13 -0400 | [diff] [blame] | 63 | #include <power/power.h> |
Kumar Gala | ccad5bf | 2017-04-21 10:03:20 -0500 | [diff] [blame] | 64 | u32_t loapic_suspend_buf[LOPIC_SUSPEND_BITS_REQD / 32] = {0}; |
| 65 | static u32_t loapic_device_power_state = DEVICE_PM_ACTIVE_STATE; |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 66 | #endif |
| 67 | |
Charles E. Youse | e9f6cb2 | 2019-06-07 15:17:13 -0700 | [diff] [blame] | 68 | /* |
| 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 |
| 76 | void z_x2apic_eoi(void) |
| 77 | { |
| 78 | x86_write_x2apic(LOAPIC_EOI, 0); |
| 79 | } |
| 80 | #endif |
| 81 | |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 82 | /** |
| 83 | * |
Anas Nashif | f367f07 | 2015-07-01 17:51:40 -0400 | [diff] [blame] | 84 | * @brief Initialize the Local APIC or xAPIC |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 85 | * |
| 86 | * This routine initializes Local APIC or xAPIC. |
| 87 | * |
Anas Nashif | 1362e3c | 2015-07-01 17:29:04 -0400 | [diff] [blame] | 88 | * @return N/A |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 89 | * |
| 90 | */ |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 91 | |
Patrik Flykt | 97b3bd1 | 2019-03-12 15:15:42 -0600 | [diff] [blame] | 92 | static int loapic_init(struct device *unused) |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 93 | { |
Dirk Brandewie | be1b1a4 | 2015-09-15 09:17:38 -0700 | [diff] [blame] | 94 | ARG_UNUSED(unused); |
Kumar Gala | ccad5bf | 2017-04-21 10:03:20 -0500 | [diff] [blame] | 95 | s32_t loApicMaxLvt; /* local APIC Max LVT */ |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 96 | |
Charles E. Youse | 9a1e927 | 2019-06-07 16:26:44 -0700 | [diff] [blame] | 97 | /* |
| 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. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 116 | loApicMaxLvt = (x86_read_loapic(LOAPIC_VER) & LOAPIC_MAXLVT_MASK) >> 16; |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 117 | |
| 118 | /* reset the DFR, TPR, TIMER_CONFIG, and TIMER_ICR */ |
| 119 | |
Charles E. Youse | 0fe4e1b | 2019-06-05 10:28:38 -0700 | [diff] [blame] | 120 | #ifndef CONFIG_X2APIC |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 121 | x86_write_loapic(LOAPIC_DFR, 0xffffffff); /* no DFR in x2APIC mode */ |
Gustavo Lima Chaves | 9bb07ff | 2017-10-11 14:17:12 -0700 | [diff] [blame] | 122 | #endif |
Gustavo Lima Chaves | 1a8e72c | 2017-10-11 14:08:17 -0700 | [diff] [blame] | 123 | |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 124 | x86_write_loapic(LOAPIC_TPR, 0x0); |
| 125 | x86_write_loapic(LOAPIC_TIMER_CONFIG, 0x0); |
| 126 | x86_write_loapic(LOAPIC_TIMER_ICR, 0x0); |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 127 | |
| 128 | /* program Local Vector Table for the Virtual Wire Mode */ |
| 129 | |
Gustavo Lima Chaves | 97a8716 | 2017-10-11 14:13:00 -0700 | [diff] [blame] | 130 | /* skip LINT0/LINT1 for Jailhouse guest case, because we won't |
| 131 | * ever be waiting for interrupts on those |
| 132 | */ |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 133 | /* set LINT0: extInt, high-polarity, edge-trigger, not-masked */ |
| 134 | |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 135 | x86_write_loapic(LOAPIC_LINT0, (x86_read_loapic(LOAPIC_LINT0) & |
Gustavo Lima Chaves | 1a8e72c | 2017-10-11 14:08:17 -0700 | [diff] [blame] | 136 | ~(LOAPIC_MODE | LOAPIC_LOW | |
| 137 | LOAPIC_LEVEL | LOAPIC_LVT_MASKED)) | |
| 138 | (LOAPIC_EXT | LOAPIC_HIGH | LOAPIC_EDGE)); |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 139 | |
| 140 | /* set LINT1: NMI, high-polarity, edge-trigger, not-masked */ |
| 141 | |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 142 | x86_write_loapic(LOAPIC_LINT1, (x86_read_loapic(LOAPIC_LINT1) & |
Gustavo Lima Chaves | 1a8e72c | 2017-10-11 14:08:17 -0700 | [diff] [blame] | 143 | ~(LOAPIC_MODE | LOAPIC_LOW | |
| 144 | LOAPIC_LEVEL | LOAPIC_LVT_MASKED)) | |
| 145 | (LOAPIC_NMI | LOAPIC_HIGH | LOAPIC_EDGE)); |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 146 | |
| 147 | /* lock the Local APIC interrupts */ |
| 148 | |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 149 | x86_write_loapic(LOAPIC_TIMER, LOAPIC_LVT_MASKED); |
| 150 | x86_write_loapic(LOAPIC_ERROR, LOAPIC_LVT_MASKED); |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 151 | |
Anas Nashif | 4c32258 | 2019-06-04 10:52:23 -0400 | [diff] [blame] | 152 | if (loApicMaxLvt >= LOAPIC_LVT_P6) { |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 153 | x86_write_loapic(LOAPIC_PMC, LOAPIC_LVT_MASKED); |
Anas Nashif | 4c32258 | 2019-06-04 10:52:23 -0400 | [diff] [blame] | 154 | } |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 155 | |
Anas Nashif | 4c32258 | 2019-06-04 10:52:23 -0400 | [diff] [blame] | 156 | if (loApicMaxLvt >= LOAPIC_LVT_PENTIUM4) { |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 157 | x86_write_loapic(LOAPIC_THERMAL, LOAPIC_LVT_MASKED); |
Anas Nashif | 4c32258 | 2019-06-04 10:52:23 -0400 | [diff] [blame] | 158 | } |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 159 | |
Andrew Boie | c25d6c5 | 2015-12-09 14:53:41 -0800 | [diff] [blame] | 160 | #if CONFIG_LOAPIC_SPURIOUS_VECTOR |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 161 | x86_write_loapic(LOAPIC_SVR, (x86_read_loapic(LOAPIC_SVR) & 0xFFFFFF00) | |
Gustavo Lima Chaves | 1a8e72c | 2017-10-11 14:08:17 -0700 | [diff] [blame] | 162 | (LOAPIC_SPURIOUS_VECTOR_ID & 0xFF)); |
Andrew Boie | c25d6c5 | 2015-12-09 14:53:41 -0800 | [diff] [blame] | 163 | #endif |
| 164 | |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 165 | /* discard a pending interrupt if any */ |
Andrew Boie | e98ac23 | 2016-08-02 12:05:08 -0700 | [diff] [blame] | 166 | #if CONFIG_EOI_FORWARDING_BUG |
Patrik Flykt | 4344e27 | 2019-03-08 14:19:05 -0700 | [diff] [blame] | 167 | z_lakemont_eoi(); |
Andrew Boie | e98ac23 | 2016-08-02 12:05:08 -0700 | [diff] [blame] | 168 | #else |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 169 | x86_write_loapic(LOAPIC_EOI, 0); |
Andrew Boie | e98ac23 | 2016-08-02 12:05:08 -0700 | [diff] [blame] | 170 | #endif |
| 171 | |
Dirk Brandewie | be1b1a4 | 2015-09-15 09:17:38 -0700 | [diff] [blame] | 172 | return 0; |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 173 | } |
| 174 | |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 175 | /** |
| 176 | * |
Anas Nashif | f367f07 | 2015-07-01 17:51:40 -0400 | [diff] [blame] | 177 | * @brief Set the vector field in the specified RTE |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 178 | * |
Andrew Boie | 325cae5 | 2016-09-22 11:20:26 -0700 | [diff] [blame] | 179 | * This associates an IRQ with the desired vector in the IDT. |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 180 | * |
Anas Nashif | 1362e3c | 2015-07-01 17:29:04 -0400 | [diff] [blame] | 181 | * @return N/A |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 182 | */ |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 183 | |
Patrik Flykt | 4344e27 | 2019-03-08 14:19:05 -0700 | [diff] [blame] | 184 | void z_loapic_int_vec_set(unsigned int irq, /* IRQ number of the interrupt */ |
Peter Mitsis | 2a4a6cf | 2015-07-27 11:02:41 -0400 | [diff] [blame] | 185 | unsigned int vector /* vector to copy into the LVT */ |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 186 | ) |
| 187 | { |
Flavio Ceolin | 0866d18 | 2018-08-14 17:57:08 -0700 | [diff] [blame] | 188 | unsigned int oldLevel; /* previous interrupt lock level */ |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 189 | |
| 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-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 203 | /* update the 'vector' bits in the LVT */ |
| 204 | |
| 205 | oldLevel = irq_lock(); |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 206 | x86_write_loapic(LOAPIC_TIMER + (irq * 0x10), |
| 207 | (x86_read_loapic(LOAPIC_TIMER + (irq * 0x10)) & |
Gustavo Lima Chaves | 1a8e72c | 2017-10-11 14:08:17 -0700 | [diff] [blame] | 208 | ~LOAPIC_VECTOR) | vector); |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 209 | irq_unlock(oldLevel); |
| 210 | } |
| 211 | |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 212 | /** |
| 213 | * |
Anas Nashif | f367f07 | 2015-07-01 17:51:40 -0400 | [diff] [blame] | 214 | * @brief Enable an individual LOAPIC interrupt (IRQ) |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 215 | * |
Dan Kalowsky | 3a109b1 | 2015-10-20 09:42:33 -0700 | [diff] [blame] | 216 | * @param irq the IRQ number of the interrupt |
| 217 | * |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 218 | * This routine clears the interrupt mask bit in the LVT for the specified IRQ |
| 219 | * |
Anas Nashif | 1362e3c | 2015-07-01 17:29:04 -0400 | [diff] [blame] | 220 | * @return N/A |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 221 | */ |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 222 | |
Patrik Flykt | 4344e27 | 2019-03-08 14:19:05 -0700 | [diff] [blame] | 223 | void z_loapic_irq_enable(unsigned int irq) |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 224 | { |
Flavio Ceolin | 0866d18 | 2018-08-14 17:57:08 -0700 | [diff] [blame] | 225 | unsigned int oldLevel; /* previous interrupt lock level */ |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 226 | |
| 227 | /* |
| 228 | * See the comments in _LoApicLvtVecSet() regarding IRQ to LVT mappings |
| 229 | * and ths assumption concerning LVT spacing. |
| 230 | */ |
| 231 | |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 232 | /* clear the mask bit in the LVT */ |
| 233 | |
| 234 | oldLevel = irq_lock(); |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 235 | x86_write_loapic(LOAPIC_TIMER + (irq * 0x10), |
| 236 | x86_read_loapic(LOAPIC_TIMER + (irq * 0x10)) & |
Gustavo Lima Chaves | 1a8e72c | 2017-10-11 14:08:17 -0700 | [diff] [blame] | 237 | ~LOAPIC_LVT_MASKED); |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 238 | irq_unlock(oldLevel); |
| 239 | } |
| 240 | |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 241 | /** |
| 242 | * |
Anas Nashif | f367f07 | 2015-07-01 17:51:40 -0400 | [diff] [blame] | 243 | * @brief Disable an individual LOAPIC interrupt (IRQ) |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 244 | * |
Dan Kalowsky | 3a109b1 | 2015-10-20 09:42:33 -0700 | [diff] [blame] | 245 | * @param irq the IRQ number of the interrupt |
| 246 | * |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 247 | * This routine clears the interrupt mask bit in the LVT for the specified IRQ |
| 248 | * |
Anas Nashif | 1362e3c | 2015-07-01 17:29:04 -0400 | [diff] [blame] | 249 | * @return N/A |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 250 | */ |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 251 | |
Patrik Flykt | 4344e27 | 2019-03-08 14:19:05 -0700 | [diff] [blame] | 252 | void z_loapic_irq_disable(unsigned int irq) |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 253 | { |
Flavio Ceolin | 0866d18 | 2018-08-14 17:57:08 -0700 | [diff] [blame] | 254 | unsigned int oldLevel; /* previous interrupt lock level */ |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 255 | |
| 256 | /* |
| 257 | * See the comments in _LoApicLvtVecSet() regarding IRQ to LVT mappings |
| 258 | * and ths assumption concerning LVT spacing. |
| 259 | */ |
| 260 | |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 261 | /* set the mask bit in the LVT */ |
| 262 | |
| 263 | oldLevel = irq_lock(); |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 264 | x86_write_loapic(LOAPIC_TIMER + (irq * 0x10), |
| 265 | x86_read_loapic(LOAPIC_TIMER + (irq * 0x10)) | |
Gustavo Lima Chaves | 1a8e72c | 2017-10-11 14:08:17 -0700 | [diff] [blame] | 266 | LOAPIC_LVT_MASKED); |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 267 | irq_unlock(oldLevel); |
| 268 | } |
Yonattan Louise | d2108bf | 2015-08-21 19:10:32 -0500 | [diff] [blame] | 269 | |
| 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. Kinder | 896cf7a | 2017-04-19 10:45:34 -0700 | [diff] [blame] | 276 | * in service. And the higher vector is the identification of the interrupt |
Yonattan Louise | d2108bf | 2015-08-21 19:10:32 -0500 | [diff] [blame] | 277 | * being currently processed. |
| 278 | * |
Andrew Boie | a69ea78 | 2016-07-12 11:42:18 -0700 | [diff] [blame] | 279 | * This function must be called with interrupts locked in interrupt context. |
| 280 | * |
Yonattan Louise | d2108bf | 2015-08-21 19:10:32 -0500 | [diff] [blame] | 281 | * 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 Boie | eec13ca | 2016-09-08 11:01:23 -0700 | [diff] [blame] | 295 | * @return The vector of the interrupt that is currently being processed, or -1 |
| 296 | * if no IRQ is being serviced. |
Yonattan Louise | d2108bf | 2015-08-21 19:10:32 -0500 | [diff] [blame] | 297 | */ |
Charles E. Youse | 0325a3d | 2019-06-28 13:06:37 -0700 | [diff] [blame^] | 298 | int z_irq_controller_isr_vector_get(void) |
Yonattan Louise | d2108bf | 2015-08-21 19:10:32 -0500 | [diff] [blame] | 299 | { |
Andrew Boie | a69ea78 | 2016-07-12 11:42:18 -0700 | [diff] [blame] | 300 | int pReg, block; |
Yonattan Louise | d2108bf | 2015-08-21 19:10:32 -0500 | [diff] [blame] | 301 | |
Andrew Boie | eec13ca | 2016-09-08 11:01:23 -0700 | [diff] [blame] | 302 | /* 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. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 306 | pReg = x86_read_loapic(LOAPIC_ISR + (block * 0x10)); |
Andrew Boie | a69ea78 | 2016-07-12 11:42:18 -0700 | [diff] [blame] | 307 | if (pReg) { |
| 308 | return (block * 32) + (find_msb_set(pReg) - 1); |
Yonattan Louise | d2108bf | 2015-08-21 19:10:32 -0500 | [diff] [blame] | 309 | } |
Yonattan Louise | d2108bf | 2015-08-21 19:10:32 -0500 | [diff] [blame] | 310 | |
Andrew Boie | a69ea78 | 2016-07-12 11:42:18 -0700 | [diff] [blame] | 311 | } |
Andrew Boie | eec13ca | 2016-09-08 11:01:23 -0700 | [diff] [blame] | 312 | return -1; |
Yonattan Louise | d2108bf | 2015-08-21 19:10:32 -0500 | [diff] [blame] | 313 | } |
Daniel Leung | 921ee03 | 2015-12-08 11:17:56 -0800 | [diff] [blame] | 314 | |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 315 | #ifdef CONFIG_DEVICE_POWER_MANAGEMENT |
amirkapl | c490219 | 2016-09-11 19:17:19 +0300 | [diff] [blame] | 316 | static int loapic_suspend(struct device *port) |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 317 | { |
Gustavo Lima Chaves | 1a8e72c | 2017-10-11 14:08:17 -0700 | [diff] [blame] | 318 | volatile u32_t lvt; /* local vector table entry value */ |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 319 | int loapic_irq; |
| 320 | |
| 321 | ARG_UNUSED(port); |
| 322 | |
Flavio Ceolin | da49f2e | 2018-09-11 19:09:03 -0700 | [diff] [blame] | 323 | (void)memset(loapic_suspend_buf, 0, (LOPIC_SUSPEND_BITS_REQD >> 3)); |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 324 | |
| 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. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 332 | lvt = x86_read_loapic(LOAPIC_TIMER + (loapic_irq * 0x10)); |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 333 | |
Patrik Flykt | 24d7143 | 2019-03-26 19:57:45 -0600 | [diff] [blame] | 334 | if ((lvt & LOAPIC_LVT_MASKED) == 0U) { |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 335 | sys_bitfield_set_bit((mem_addr_t)loapic_suspend_buf, |
| 336 | loapic_irq); |
| 337 | } |
| 338 | } |
| 339 | } |
amirkapl | c490219 | 2016-09-11 19:17:19 +0300 | [diff] [blame] | 340 | loapic_device_power_state = DEVICE_PM_SUSPEND_STATE; |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 341 | return 0; |
| 342 | } |
| 343 | |
amirkapl | c490219 | 2016-09-11 19:17:19 +0300 | [diff] [blame] | 344 | int loapic_resume(struct device *port) |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 345 | { |
| 346 | int loapic_irq; |
| 347 | |
| 348 | ARG_UNUSED(port); |
| 349 | |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 350 | /* Assuming all loapic device registers lose their state, the call to |
Patrik Flykt | 97b3bd1 | 2019-03-12 15:15:42 -0600 | [diff] [blame] | 351 | * z_loapic_init(), should bring all the registers to a sane state. |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 352 | */ |
Patrik Flykt | 97b3bd1 | 2019-03-12 15:15:42 -0600 | [diff] [blame] | 353 | loapic_init(NULL); |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 354 | |
| 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 Flykt | 4344e27 | 2019-03-08 14:19:05 -0700 | [diff] [blame] | 359 | z_loapic_int_vec_set(loapic_irq, |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 360 | _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 Flykt | 4344e27 | 2019-03-08 14:19:05 -0700 | [diff] [blame] | 364 | z_loapic_irq_enable(loapic_irq); |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 365 | } |
| 366 | } |
| 367 | } |
amirkapl | c490219 | 2016-09-11 19:17:19 +0300 | [diff] [blame] | 368 | loapic_device_power_state = DEVICE_PM_ACTIVE_STATE; |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 369 | |
| 370 | return 0; |
| 371 | } |
| 372 | |
amirkapl | c490219 | 2016-09-11 19:17:19 +0300 | [diff] [blame] | 373 | /* |
| 374 | * Implements the driver control management functionality |
| 375 | * the *context may include IN data or/and OUT data |
| 376 | */ |
Kumar Gala | ccad5bf | 2017-04-21 10:03:20 -0500 | [diff] [blame] | 377 | static int loapic_device_ctrl(struct device *port, u32_t ctrl_command, |
Ramakrishna Pallala | e1639b5 | 2019-02-14 09:35:42 +0530 | [diff] [blame] | 378 | void *context, device_pm_cb cb, void *arg) |
amirkapl | c490219 | 2016-09-11 19:17:19 +0300 | [diff] [blame] | 379 | { |
Ramakrishna Pallala | e1639b5 | 2019-02-14 09:35:42 +0530 | [diff] [blame] | 380 | int ret = 0; |
| 381 | |
amirkapl | c490219 | 2016-09-11 19:17:19 +0300 | [diff] [blame] | 382 | if (ctrl_command == DEVICE_PM_SET_POWER_STATE) { |
Kumar Gala | ccad5bf | 2017-04-21 10:03:20 -0500 | [diff] [blame] | 383 | if (*((u32_t *)context) == DEVICE_PM_SUSPEND_STATE) { |
Ramakrishna Pallala | e1639b5 | 2019-02-14 09:35:42 +0530 | [diff] [blame] | 384 | ret = loapic_suspend(port); |
Kumar Gala | ccad5bf | 2017-04-21 10:03:20 -0500 | [diff] [blame] | 385 | } else if (*((u32_t *)context) == DEVICE_PM_ACTIVE_STATE) { |
Ramakrishna Pallala | e1639b5 | 2019-02-14 09:35:42 +0530 | [diff] [blame] | 386 | ret = loapic_resume(port); |
amirkapl | c490219 | 2016-09-11 19:17:19 +0300 | [diff] [blame] | 387 | } |
| 388 | } else if (ctrl_command == DEVICE_PM_GET_POWER_STATE) { |
Kumar Gala | ccad5bf | 2017-04-21 10:03:20 -0500 | [diff] [blame] | 389 | *((u32_t *)context) = loapic_device_power_state; |
amirkapl | c490219 | 2016-09-11 19:17:19 +0300 | [diff] [blame] | 390 | } |
| 391 | |
Ramakrishna Pallala | e1639b5 | 2019-02-14 09:35:42 +0530 | [diff] [blame] | 392 | if (cb) { |
| 393 | cb(port, ret, context, arg); |
| 394 | } |
| 395 | |
| 396 | return ret; |
amirkapl | c490219 | 2016-09-11 19:17:19 +0300 | [diff] [blame] | 397 | } |
| 398 | |
Patrik Flykt | 97b3bd1 | 2019-03-12 15:15:42 -0600 | [diff] [blame] | 399 | SYS_DEVICE_DEFINE("loapic", loapic_init, loapic_device_ctrl, PRE_KERNEL_1, |
amirkapl | c490219 | 2016-09-11 19:17:19 +0300 | [diff] [blame] | 400 | CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 401 | #else |
Patrik Flykt | 97b3bd1 | 2019-03-12 15:15:42 -0600 | [diff] [blame] | 402 | SYS_INIT(loapic_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 403 | #endif /* CONFIG_DEVICE_POWER_MANAGEMENT */ |
| 404 | |
Andrew Boie | c25d6c5 | 2015-12-09 14:53:41 -0800 | [diff] [blame] | 405 | |
| 406 | #if CONFIG_LOAPIC_SPURIOUS_VECTOR |
Patrik Flykt | 97b3bd1 | 2019-03-12 15:15:42 -0600 | [diff] [blame] | 407 | extern void z_loapic_spurious_handler(void); |
Andrew Boie | c25d6c5 | 2015-12-09 14:53:41 -0800 | [diff] [blame] | 408 | |
Patrik Flykt | 97b3bd1 | 2019-03-12 15:15:42 -0600 | [diff] [blame] | 409 | NANO_CPU_INT_REGISTER(z_loapic_spurious_handler, NANO_SOFT_IRQ, |
Andrew Boie | c25d6c5 | 2015-12-09 14:53:41 -0800 | [diff] [blame] | 410 | LOAPIC_SPURIOUS_VECTOR_ID >> 4, |
| 411 | LOAPIC_SPURIOUS_VECTOR_ID, 0); |
| 412 | #endif |