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 */ |
Tomasz Bursztyka | dfe9386 | 2020-03-13 16:20:49 +0100 | [diff] [blame] | 21 | #include <device.h> |
Anas Nashif | 43a4933 | 2019-06-21 12:54:15 -0400 | [diff] [blame] | 22 | #include <drivers/interrupt_controller/sysapic.h> |
Tomasz Bursztyka | 915f4ac | 2021-03-09 19:54:42 +0100 | [diff] [blame] | 23 | #include <drivers/interrupt_controller/ioapic.h> |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 24 | |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 25 | /* 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-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 49 | |
| 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 Boie | c25d6c5 | 2015-12-09 14:53:41 -0800 | [diff] [blame] | 55 | #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-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 60 | |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 61 | #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 Nashif | dd931f9 | 2020-09-01 18:31:40 -0400 | [diff] [blame] | 63 | #ifdef CONFIG_PM_DEVICE |
Gerard Marull-Paretas | 3863be0 | 2021-05-03 17:26:38 +0200 | [diff] [blame] | 64 | #include <pm/device.h> |
Daniel Leung | e498748 | 2021-03-17 13:47:56 -0700 | [diff] [blame] | 65 | __pinned_bss |
Kumar Gala | a1b77fd | 2020-05-27 11:26:57 -0500 | [diff] [blame] | 66 | uint32_t loapic_suspend_buf[LOPIC_SUSPEND_BITS_REQD / 32] = {0}; |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 67 | #endif |
| 68 | |
Andrew Boie | ee3c50b | 2020-06-26 12:09:01 -0700 | [diff] [blame] | 69 | #ifdef DEVICE_MMIO_IS_IN_RAM |
Daniel Leung | e498748 | 2021-03-17 13:47:56 -0700 | [diff] [blame] | 70 | __pinned_bss |
Andrew Boie | ee3c50b | 2020-06-26 12:09:01 -0700 | [diff] [blame] | 71 | mm_reg_t z_loapic_regs; |
| 72 | #endif |
| 73 | |
Daniel Leung | e498748 | 2021-03-17 13:47:56 -0700 | [diff] [blame] | 74 | __pinned_func |
Andrew Boie | ee3c50b | 2020-06-26 12:09:01 -0700 | [diff] [blame] | 75 | void send_eoi(void) |
| 76 | { |
| 77 | x86_write_xapic(LOAPIC_EOI, 0); |
| 78 | } |
| 79 | |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 80 | /** |
Charles E. Youse | a981f51 | 2019-09-28 16:58:22 -0400 | [diff] [blame] | 81 | * @brief Enable and initialize the local APIC. |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 82 | * |
Charles E. Youse | a981f51 | 2019-09-28 16:58:22 -0400 | [diff] [blame] | 83 | * Called from early assembly layer (e.g., crt0.S). |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 84 | */ |
Daniel Leung | e498748 | 2021-03-17 13:47:56 -0700 | [diff] [blame] | 85 | __pinned_func |
Zide Chen | d27f6cb | 2020-02-10 14:09:05 -0800 | [diff] [blame] | 86 | void z_loapic_enable(unsigned char cpu_number) |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 87 | { |
Kumar Gala | a1b77fd | 2020-05-27 11:26:57 -0500 | [diff] [blame] | 88 | int32_t loApicMaxLvt; /* local APIC Max LVT */ |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 89 | |
Andrew Boie | ee3c50b | 2020-06-26 12:09:01 -0700 | [diff] [blame] | 90 | #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 Chen | d27f6cb | 2020-02-10 14:09:05 -0800 | [diff] [blame] | 94 | #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. Youse | 9a1e927 | 2019-06-07 16:26:44 -0700 | [diff] [blame] | 111 | /* |
| 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 Gala | a1b77fd | 2020-05-27 11:26:57 -0500 | [diff] [blame] | 125 | uint64_t msr = z_x86_msr_read(X86_APIC_BASE_MSR); |
Charles E. Youse | 9a1e927 | 2019-06-07 16:26:44 -0700 | [diff] [blame] | 126 | msr |= X86_APIC_BASE_MSR_X2APIC; |
| 127 | z_x86_msr_write(X86_APIC_BASE_MSR, msr); |
| 128 | #endif |
| 129 | |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 130 | loApicMaxLvt = (x86_read_loapic(LOAPIC_VER) & LOAPIC_MAXLVT_MASK) >> 16; |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 131 | |
| 132 | /* reset the DFR, TPR, TIMER_CONFIG, and TIMER_ICR */ |
| 133 | |
Charles E. Youse | 0fe4e1b | 2019-06-05 10:28:38 -0700 | [diff] [blame] | 134 | #ifndef CONFIG_X2APIC |
Zide Chen | d27f6cb | 2020-02-10 14:09:05 -0800 | [diff] [blame] | 135 | /* Flat model */ |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 136 | x86_write_loapic(LOAPIC_DFR, 0xffffffff); /* no DFR in x2APIC mode */ |
Gustavo Lima Chaves | 9bb07ff | 2017-10-11 14:17:12 -0700 | [diff] [blame] | 137 | #endif |
Gustavo Lima Chaves | 1a8e72c | 2017-10-11 14:08:17 -0700 | [diff] [blame] | 138 | |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 139 | x86_write_loapic(LOAPIC_TPR, 0x0); |
| 140 | x86_write_loapic(LOAPIC_TIMER_CONFIG, 0x0); |
| 141 | x86_write_loapic(LOAPIC_TIMER_ICR, 0x0); |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 142 | |
| 143 | /* program Local Vector Table for the Virtual Wire Mode */ |
| 144 | |
Gustavo Lima Chaves | 97a8716 | 2017-10-11 14:13:00 -0700 | [diff] [blame] | 145 | /* skip LINT0/LINT1 for Jailhouse guest case, because we won't |
| 146 | * ever be waiting for interrupts on those |
| 147 | */ |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 148 | /* set LINT0: extInt, high-polarity, edge-trigger, not-masked */ |
| 149 | |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 150 | x86_write_loapic(LOAPIC_LINT0, (x86_read_loapic(LOAPIC_LINT0) & |
Gustavo Lima Chaves | 1a8e72c | 2017-10-11 14:08:17 -0700 | [diff] [blame] | 151 | ~(LOAPIC_MODE | LOAPIC_LOW | |
| 152 | LOAPIC_LEVEL | LOAPIC_LVT_MASKED)) | |
| 153 | (LOAPIC_EXT | LOAPIC_HIGH | LOAPIC_EDGE)); |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 154 | |
| 155 | /* set LINT1: NMI, high-polarity, edge-trigger, not-masked */ |
| 156 | |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 157 | x86_write_loapic(LOAPIC_LINT1, (x86_read_loapic(LOAPIC_LINT1) & |
Gustavo Lima Chaves | 1a8e72c | 2017-10-11 14:08:17 -0700 | [diff] [blame] | 158 | ~(LOAPIC_MODE | LOAPIC_LOW | |
| 159 | LOAPIC_LEVEL | LOAPIC_LVT_MASKED)) | |
| 160 | (LOAPIC_NMI | LOAPIC_HIGH | LOAPIC_EDGE)); |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 161 | |
| 162 | /* lock the Local APIC interrupts */ |
| 163 | |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 164 | x86_write_loapic(LOAPIC_TIMER, LOAPIC_LVT_MASKED); |
| 165 | x86_write_loapic(LOAPIC_ERROR, LOAPIC_LVT_MASKED); |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 166 | |
Anas Nashif | 4c32258 | 2019-06-04 10:52:23 -0400 | [diff] [blame] | 167 | if (loApicMaxLvt >= LOAPIC_LVT_P6) { |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 168 | x86_write_loapic(LOAPIC_PMC, LOAPIC_LVT_MASKED); |
Anas Nashif | 4c32258 | 2019-06-04 10:52:23 -0400 | [diff] [blame] | 169 | } |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 170 | |
Anas Nashif | 4c32258 | 2019-06-04 10:52:23 -0400 | [diff] [blame] | 171 | if (loApicMaxLvt >= LOAPIC_LVT_PENTIUM4) { |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 172 | x86_write_loapic(LOAPIC_THERMAL, LOAPIC_LVT_MASKED); |
Anas Nashif | 4c32258 | 2019-06-04 10:52:23 -0400 | [diff] [blame] | 173 | } |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 174 | |
Andrew Boie | c25d6c5 | 2015-12-09 14:53:41 -0800 | [diff] [blame] | 175 | #if CONFIG_LOAPIC_SPURIOUS_VECTOR |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 176 | x86_write_loapic(LOAPIC_SVR, (x86_read_loapic(LOAPIC_SVR) & 0xFFFFFF00) | |
Gustavo Lima Chaves | 1a8e72c | 2017-10-11 14:08:17 -0700 | [diff] [blame] | 177 | (LOAPIC_SPURIOUS_VECTOR_ID & 0xFF)); |
Andrew Boie | c25d6c5 | 2015-12-09 14:53:41 -0800 | [diff] [blame] | 178 | #endif |
| 179 | |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 180 | /* discard a pending interrupt if any */ |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 181 | x86_write_loapic(LOAPIC_EOI, 0); |
Charles E. Youse | a981f51 | 2019-09-28 16:58:22 -0400 | [diff] [blame] | 182 | } |
Andrew Boie | e98ac23 | 2016-08-02 12:05:08 -0700 | [diff] [blame] | 183 | |
Charles E. Youse | a981f51 | 2019-09-28 16:58:22 -0400 | [diff] [blame] | 184 | /** |
| 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 Leung | e498748 | 2021-03-17 13:47:56 -0700 | [diff] [blame] | 191 | __boot_func |
Tomasz Bursztyka | e18fcbb | 2020-04-30 20:33:38 +0200 | [diff] [blame] | 192 | static int loapic_init(const struct device *unused) |
Charles E. Youse | a981f51 | 2019-09-28 16:58:22 -0400 | [diff] [blame] | 193 | { |
| 194 | ARG_UNUSED(unused); |
Dirk Brandewie | be1b1a4 | 2015-09-15 09:17:38 -0700 | [diff] [blame] | 195 | return 0; |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 196 | } |
| 197 | |
Tomasz Bursztyka | 915f4ac | 2021-03-09 19:54:42 +0100 | [diff] [blame] | 198 | |
Daniel Leung | e498748 | 2021-03-17 13:47:56 -0700 | [diff] [blame] | 199 | __pinned_func |
Tomasz Bursztyka | 915f4ac | 2021-03-09 19:54:42 +0100 | [diff] [blame] | 200 | uint32_t z_loapic_irq_base(void) |
| 201 | { |
| 202 | return z_ioapic_num_rtes(); |
| 203 | } |
| 204 | |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 205 | /** |
| 206 | * |
Anas Nashif | f367f07 | 2015-07-01 17:51:40 -0400 | [diff] [blame] | 207 | * @brief Set the vector field in the specified RTE |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 208 | * |
Andrew Boie | 325cae5 | 2016-09-22 11:20:26 -0700 | [diff] [blame] | 209 | * This associates an IRQ with the desired vector in the IDT. |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 210 | * |
Anas Nashif | 1362e3c | 2015-07-01 17:29:04 -0400 | [diff] [blame] | 211 | * @return N/A |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 212 | */ |
Daniel Leung | e498748 | 2021-03-17 13:47:56 -0700 | [diff] [blame] | 213 | __boot_func |
Patrik Flykt | 4344e27 | 2019-03-08 14:19:05 -0700 | [diff] [blame] | 214 | 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] | 215 | unsigned int vector /* vector to copy into the LVT */ |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 216 | ) |
| 217 | { |
Flavio Ceolin | 0866d18 | 2018-08-14 17:57:08 -0700 | [diff] [blame] | 218 | unsigned int oldLevel; /* previous interrupt lock level */ |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 219 | |
| 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-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 233 | /* update the 'vector' bits in the LVT */ |
| 234 | |
| 235 | oldLevel = irq_lock(); |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 236 | x86_write_loapic(LOAPIC_TIMER + (irq * 0x10), |
| 237 | (x86_read_loapic(LOAPIC_TIMER + (irq * 0x10)) & |
Gustavo Lima Chaves | 1a8e72c | 2017-10-11 14:08:17 -0700 | [diff] [blame] | 238 | ~LOAPIC_VECTOR) | vector); |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 239 | irq_unlock(oldLevel); |
| 240 | } |
| 241 | |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 242 | /** |
| 243 | * |
Anas Nashif | f367f07 | 2015-07-01 17:51:40 -0400 | [diff] [blame] | 244 | * @brief Enable an individual LOAPIC interrupt (IRQ) |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 245 | * |
Dan Kalowsky | 3a109b1 | 2015-10-20 09:42:33 -0700 | [diff] [blame] | 246 | * @param irq the IRQ number of the interrupt |
| 247 | * |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 248 | * This routine clears the interrupt mask bit in the LVT for the specified IRQ |
| 249 | * |
Anas Nashif | 1362e3c | 2015-07-01 17:29:04 -0400 | [diff] [blame] | 250 | * @return N/A |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 251 | */ |
Daniel Leung | e498748 | 2021-03-17 13:47:56 -0700 | [diff] [blame] | 252 | __pinned_func |
Patrik Flykt | 4344e27 | 2019-03-08 14:19:05 -0700 | [diff] [blame] | 253 | void z_loapic_irq_enable(unsigned int irq) |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 254 | { |
Flavio Ceolin | 0866d18 | 2018-08-14 17:57:08 -0700 | [diff] [blame] | 255 | unsigned int oldLevel; /* previous interrupt lock level */ |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 256 | |
| 257 | /* |
| 258 | * See the comments in _LoApicLvtVecSet() regarding IRQ to LVT mappings |
| 259 | * and ths assumption concerning LVT spacing. |
| 260 | */ |
| 261 | |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 262 | /* clear the mask bit in the LVT */ |
| 263 | |
| 264 | oldLevel = irq_lock(); |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 265 | x86_write_loapic(LOAPIC_TIMER + (irq * 0x10), |
| 266 | x86_read_loapic(LOAPIC_TIMER + (irq * 0x10)) & |
Gustavo Lima Chaves | 1a8e72c | 2017-10-11 14:08:17 -0700 | [diff] [blame] | 267 | ~LOAPIC_LVT_MASKED); |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 268 | irq_unlock(oldLevel); |
| 269 | } |
| 270 | |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 271 | /** |
| 272 | * |
Anas Nashif | f367f07 | 2015-07-01 17:51:40 -0400 | [diff] [blame] | 273 | * @brief Disable an individual LOAPIC interrupt (IRQ) |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 274 | * |
Dan Kalowsky | 3a109b1 | 2015-10-20 09:42:33 -0700 | [diff] [blame] | 275 | * @param irq the IRQ number of the interrupt |
| 276 | * |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 277 | * This routine clears the interrupt mask bit in the LVT for the specified IRQ |
| 278 | * |
Anas Nashif | 1362e3c | 2015-07-01 17:29:04 -0400 | [diff] [blame] | 279 | * @return N/A |
Anas Nashif | ea0d0b2 | 2015-07-01 17:22:39 -0400 | [diff] [blame] | 280 | */ |
Daniel Leung | e498748 | 2021-03-17 13:47:56 -0700 | [diff] [blame] | 281 | __pinned_func |
Patrik Flykt | 4344e27 | 2019-03-08 14:19:05 -0700 | [diff] [blame] | 282 | void z_loapic_irq_disable(unsigned int irq) |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 283 | { |
Flavio Ceolin | 0866d18 | 2018-08-14 17:57:08 -0700 | [diff] [blame] | 284 | unsigned int oldLevel; /* previous interrupt lock level */ |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 285 | |
| 286 | /* |
| 287 | * See the comments in _LoApicLvtVecSet() regarding IRQ to LVT mappings |
| 288 | * and ths assumption concerning LVT spacing. |
| 289 | */ |
| 290 | |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 291 | /* set the mask bit in the LVT */ |
| 292 | |
| 293 | oldLevel = irq_lock(); |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 294 | x86_write_loapic(LOAPIC_TIMER + (irq * 0x10), |
| 295 | x86_read_loapic(LOAPIC_TIMER + (irq * 0x10)) | |
Gustavo Lima Chaves | 1a8e72c | 2017-10-11 14:08:17 -0700 | [diff] [blame] | 296 | LOAPIC_LVT_MASKED); |
Inaky Perez-Gonzalez | 8ddf82c | 2015-04-10 16:44:37 -0700 | [diff] [blame] | 297 | irq_unlock(oldLevel); |
| 298 | } |
Yonattan Louise | d2108bf | 2015-08-21 19:10:32 -0500 | [diff] [blame] | 299 | |
| 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. Kinder | 896cf7a | 2017-04-19 10:45:34 -0700 | [diff] [blame] | 306 | * in service. And the higher vector is the identification of the interrupt |
Yonattan Louise | d2108bf | 2015-08-21 19:10:32 -0500 | [diff] [blame] | 307 | * being currently processed. |
| 308 | * |
Andrew Boie | a69ea78 | 2016-07-12 11:42:18 -0700 | [diff] [blame] | 309 | * This function must be called with interrupts locked in interrupt context. |
| 310 | * |
Yonattan Louise | d2108bf | 2015-08-21 19:10:32 -0500 | [diff] [blame] | 311 | * 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 Boie | eec13ca | 2016-09-08 11:01:23 -0700 | [diff] [blame] | 325 | * @return The vector of the interrupt that is currently being processed, or -1 |
| 326 | * if no IRQ is being serviced. |
Yonattan Louise | d2108bf | 2015-08-21 19:10:32 -0500 | [diff] [blame] | 327 | */ |
Daniel Leung | e498748 | 2021-03-17 13:47:56 -0700 | [diff] [blame] | 328 | __pinned_func |
Charles E. Youse | 0325a3d | 2019-06-28 13:06:37 -0700 | [diff] [blame] | 329 | int z_irq_controller_isr_vector_get(void) |
Yonattan Louise | d2108bf | 2015-08-21 19:10:32 -0500 | [diff] [blame] | 330 | { |
Andrew Boie | a69ea78 | 2016-07-12 11:42:18 -0700 | [diff] [blame] | 331 | int pReg, block; |
Yonattan Louise | d2108bf | 2015-08-21 19:10:32 -0500 | [diff] [blame] | 332 | |
Andrew Boie | eec13ca | 2016-09-08 11:01:23 -0700 | [diff] [blame] | 333 | /* 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. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 337 | pReg = x86_read_loapic(LOAPIC_ISR + (block * 0x10)); |
Andrew Boie | a69ea78 | 2016-07-12 11:42:18 -0700 | [diff] [blame] | 338 | if (pReg) { |
| 339 | return (block * 32) + (find_msb_set(pReg) - 1); |
Yonattan Louise | d2108bf | 2015-08-21 19:10:32 -0500 | [diff] [blame] | 340 | } |
Yonattan Louise | d2108bf | 2015-08-21 19:10:32 -0500 | [diff] [blame] | 341 | |
Andrew Boie | a69ea78 | 2016-07-12 11:42:18 -0700 | [diff] [blame] | 342 | } |
Andrew Boie | eec13ca | 2016-09-08 11:01:23 -0700 | [diff] [blame] | 343 | return -1; |
Yonattan Louise | d2108bf | 2015-08-21 19:10:32 -0500 | [diff] [blame] | 344 | } |
Daniel Leung | 921ee03 | 2015-12-08 11:17:56 -0800 | [diff] [blame] | 345 | |
Anas Nashif | dd931f9 | 2020-09-01 18:31:40 -0400 | [diff] [blame] | 346 | #ifdef CONFIG_PM_DEVICE |
Daniel Leung | e498748 | 2021-03-17 13:47:56 -0700 | [diff] [blame] | 347 | __pinned_func |
Tomasz Bursztyka | e18fcbb | 2020-04-30 20:33:38 +0200 | [diff] [blame] | 348 | static int loapic_suspend(const struct device *port) |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 349 | { |
Kumar Gala | a1b77fd | 2020-05-27 11:26:57 -0500 | [diff] [blame] | 350 | volatile uint32_t lvt; /* local vector table entry value */ |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 351 | int loapic_irq; |
| 352 | |
| 353 | ARG_UNUSED(port); |
| 354 | |
Flavio Ceolin | da49f2e | 2018-09-11 19:09:03 -0700 | [diff] [blame] | 355 | (void)memset(loapic_suspend_buf, 0, (LOPIC_SUSPEND_BITS_REQD >> 3)); |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 356 | |
| 357 | for (loapic_irq = 0; loapic_irq < LOAPIC_IRQ_COUNT; loapic_irq++) { |
| 358 | |
Tomasz Bursztyka | 915f4ac | 2021-03-09 19:54:42 +0100 | [diff] [blame] | 359 | if (_irq_to_interrupt_vector[z_loapic_irq_base() + loapic_irq]) { |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 360 | |
| 361 | /* Since vector numbers are already present in RAM/ROM, |
| 362 | * We save only the mask bits here. |
| 363 | */ |
Charles E. Youse | aaecce4 | 2019-06-06 14:36:44 -0700 | [diff] [blame] | 364 | lvt = x86_read_loapic(LOAPIC_TIMER + (loapic_irq * 0x10)); |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 365 | |
Patrik Flykt | 24d7143 | 2019-03-26 19:57:45 -0600 | [diff] [blame] | 366 | if ((lvt & LOAPIC_LVT_MASKED) == 0U) { |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 367 | sys_bitfield_set_bit((mem_addr_t)loapic_suspend_buf, |
| 368 | loapic_irq); |
| 369 | } |
| 370 | } |
| 371 | } |
Gerard Marull-Paretas | c2cf1ad | 2021-06-04 17:41:39 +0200 | [diff] [blame] | 372 | |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 373 | return 0; |
| 374 | } |
| 375 | |
Daniel Leung | e498748 | 2021-03-17 13:47:56 -0700 | [diff] [blame] | 376 | __pinned_func |
Tomasz Bursztyka | e18fcbb | 2020-04-30 20:33:38 +0200 | [diff] [blame] | 377 | int loapic_resume(const struct device *port) |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 378 | { |
| 379 | int loapic_irq; |
| 380 | |
| 381 | ARG_UNUSED(port); |
| 382 | |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 383 | /* Assuming all loapic device registers lose their state, the call to |
Patrik Flykt | 97b3bd1 | 2019-03-12 15:15:42 -0600 | [diff] [blame] | 384 | * z_loapic_init(), should bring all the registers to a sane state. |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 385 | */ |
Patrik Flykt | 97b3bd1 | 2019-03-12 15:15:42 -0600 | [diff] [blame] | 386 | loapic_init(NULL); |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 387 | |
| 388 | for (loapic_irq = 0; loapic_irq < LOAPIC_IRQ_COUNT; loapic_irq++) { |
| 389 | |
Tomasz Bursztyka | 915f4ac | 2021-03-09 19:54:42 +0100 | [diff] [blame] | 390 | if (_irq_to_interrupt_vector[z_loapic_irq_base() + loapic_irq]) { |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 391 | /* Configure vector and enable the required ones*/ |
Patrik Flykt | 4344e27 | 2019-03-08 14:19:05 -0700 | [diff] [blame] | 392 | z_loapic_int_vec_set(loapic_irq, |
Tomasz Bursztyka | 915f4ac | 2021-03-09 19:54:42 +0100 | [diff] [blame] | 393 | _irq_to_interrupt_vector[z_loapic_irq_base() + |
| 394 | loapic_irq]); |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 395 | |
| 396 | if (sys_bitfield_test_bit((mem_addr_t) loapic_suspend_buf, |
| 397 | loapic_irq)) { |
Patrik Flykt | 4344e27 | 2019-03-08 14:19:05 -0700 | [diff] [blame] | 398 | z_loapic_irq_enable(loapic_irq); |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 399 | } |
| 400 | } |
| 401 | } |
| 402 | |
| 403 | return 0; |
| 404 | } |
| 405 | |
amirkapl | c490219 | 2016-09-11 19:17:19 +0300 | [diff] [blame] | 406 | /* |
| 407 | * Implements the driver control management functionality |
| 408 | * the *context may include IN data or/and OUT data |
| 409 | */ |
Daniel Leung | e498748 | 2021-03-17 13:47:56 -0700 | [diff] [blame] | 410 | __pinned_func |
Gerard Marull-Paretas | 495672a | 2021-07-05 10:35:15 +0200 | [diff] [blame] | 411 | static int loapic_device_ctrl(const struct device *dev, |
Gerard Marull-Paretas | 7ccc1a4 | 2021-07-05 15:13:40 +0200 | [diff] [blame] | 412 | enum pm_device_action action) |
amirkapl | c490219 | 2016-09-11 19:17:19 +0300 | [diff] [blame] | 413 | { |
Ramakrishna Pallala | e1639b5 | 2019-02-14 09:35:42 +0530 | [diff] [blame] | 414 | int ret = 0; |
| 415 | |
Gerard Marull-Paretas | 7ccc1a4 | 2021-07-05 15:13:40 +0200 | [diff] [blame] | 416 | switch (action) { |
| 417 | case PM_DEVICE_ACTION_SUSPEND: |
Gerard Marull-Paretas | 495672a | 2021-07-05 10:35:15 +0200 | [diff] [blame] | 418 | ret = loapic_suspend(dev); |
| 419 | break; |
Gerard Marull-Paretas | 7ccc1a4 | 2021-07-05 15:13:40 +0200 | [diff] [blame] | 420 | case PM_DEVICE_ACTION_RESUME: |
Gerard Marull-Paretas | 495672a | 2021-07-05 10:35:15 +0200 | [diff] [blame] | 421 | ret = loapic_resume(dev); |
| 422 | break; |
| 423 | default: |
| 424 | return -ENOTSUP; |
amirkapl | c490219 | 2016-09-11 19:17:19 +0300 | [diff] [blame] | 425 | } |
| 426 | |
Ramakrishna Pallala | e1639b5 | 2019-02-14 09:35:42 +0530 | [diff] [blame] | 427 | return ret; |
amirkapl | c490219 | 2016-09-11 19:17:19 +0300 | [diff] [blame] | 428 | } |
| 429 | |
Patrik Flykt | 97b3bd1 | 2019-03-12 15:15:42 -0600 | [diff] [blame] | 430 | SYS_DEVICE_DEFINE("loapic", loapic_init, loapic_device_ctrl, PRE_KERNEL_1, |
amirkapl | c490219 | 2016-09-11 19:17:19 +0300 | [diff] [blame] | 431 | CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 432 | #else |
Patrik Flykt | 97b3bd1 | 2019-03-12 15:15:42 -0600 | [diff] [blame] | 433 | SYS_INIT(loapic_init, PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); |
Anas Nashif | dd931f9 | 2020-09-01 18:31:40 -0400 | [diff] [blame] | 434 | #endif /* CONFIG_PM_DEVICE */ |
Jithu Joseph | 09a0c2f | 2016-05-06 21:55:51 -0700 | [diff] [blame] | 435 | |
Andrew Boie | c25d6c5 | 2015-12-09 14:53:41 -0800 | [diff] [blame] | 436 | |
| 437 | #if CONFIG_LOAPIC_SPURIOUS_VECTOR |
Patrik Flykt | 97b3bd1 | 2019-03-12 15:15:42 -0600 | [diff] [blame] | 438 | extern void z_loapic_spurious_handler(void); |
Andrew Boie | c25d6c5 | 2015-12-09 14:53:41 -0800 | [diff] [blame] | 439 | |
Patrik Flykt | 97b3bd1 | 2019-03-12 15:15:42 -0600 | [diff] [blame] | 440 | NANO_CPU_INT_REGISTER(z_loapic_spurious_handler, NANO_SOFT_IRQ, |
Andrew Boie | c25d6c5 | 2015-12-09 14:53:41 -0800 | [diff] [blame] | 441 | LOAPIC_SPURIOUS_VECTOR_ID >> 4, |
| 442 | LOAPIC_SPURIOUS_VECTOR_ID, 0); |
| 443 | #endif |