1/*
2 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#include <config.h>
8#include <arch/kernel/xapic.h>
9#include <arch/kernel/x2apic.h>
10
11#ifdef CONFIG_XAPIC
12#ifdef CONFIG_USE_LOGICAL_IDS
13/* using flat cluster mode we only support 8 cores */
14compile_assert(number_of_cores_invalid_for_logical_ids, CONFIG_MAX_NUM_NODES <= 8)
15
16BOOT_CODE static void
17init_xapic_ldr(void)
18{
19    uint32_t ldr;
20
21    apic_write_reg(APIC_DEST_FORMAT, XAPIC_DFR_FLAT);
22    ldr = apic_read_reg(APIC_LOGICAL_DEST) & MASK(XAPIC_LDR_SHIFT);
23    ldr |= (BIT(getCurrentCPUIndex()) << XAPIC_LDR_SHIFT);
24    apic_write_reg(APIC_LOGICAL_DEST, ldr);
25}
26#endif /* CONFIG_USE_LOGICAL_IDS */
27
28BOOT_CODE bool_t apic_enable(void)
29{
30    apic_base_msr_t apic_base_msr;
31    apic_base_msr.words[0] = x86_rdmsr_low(IA32_APIC_BASE_MSR);
32
33    if (!apic_base_msr_get_enabled(apic_base_msr)) {
34        printf("APIC: Enabled bit not set\n");
35        return false;
36    }
37
38    if (x2apic_is_enabled()) {
39        printf("x2APIC enabled in BIOS but kernel does not support that\n");
40        return false;
41    }
42
43#ifdef CONFIG_USE_LOGICAL_IDS
44    init_xapic_ldr();
45#endif /* CONFIG_USE_LOGICAL_IDS */
46
47    return true;
48}
49
50bool_t apic_is_interrupt_pending(void)
51{
52    word_t i;
53
54    /* read 256-bit register: each 32-bit word is 16 byte aligned */
55    assert(int_irq_min % 32 == 0);
56    for (i = int_irq_min; i <= int_irq_max; i += 32) {
57        if (apic_read_reg(APIC_IRR_BASE + i / 2) != 0) {
58            return true;
59        }
60    }
61    return false;
62}
63
64BOOT_CODE void apic_send_init_ipi(cpu_id_t cpu_id)
65{
66    apic_write_icr(
67        apic_icr2_new(
68            cpu_id      /* dest */
69        ).words[0],
70        apic_icr1_new(
71            0,          /* dest_shorthand  */
72            1,          /* trigger_mode    */
73            1,          /* level           */
74            0,          /* delivery_status */
75            0,          /* dest_mode       */
76            5,          /* delivery_mode   */
77            0           /* vector          */
78        ).words[0]
79    );
80    apic_write_icr(
81        apic_icr2_new(
82            cpu_id      /* dest */
83        ).words[0],
84        apic_icr1_new(
85            0,          /* dest_shorthand  */
86            1,          /* trigger_mode    */
87            0,          /* level           */
88            0,          /* delivery_status */
89            0,          /* dest_mode       */
90            5,          /* delivery_mode   */
91            0           /* vector          */
92        ).words[0]
93    );
94}
95
96BOOT_CODE void apic_send_startup_ipi(cpu_id_t cpu_id, paddr_t startup_addr)
97{
98    /* check if 4K aligned */
99    assert(IS_ALIGNED(startup_addr, PAGE_BITS));
100    /* check if startup_addr < 640K */
101    assert(startup_addr < 0xa0000);
102    startup_addr >>= PAGE_BITS;
103
104    apic_write_icr(
105        apic_icr2_new(
106            cpu_id       /* dest */
107        ).words[0],
108        apic_icr1_new(
109            0,           /* dest_shorthand  */
110            0,           /* trigger_mode    */
111            0,           /* level           */
112            0,           /* delivery_status */
113            0,           /* dest_mode       */
114            6,           /* delivery_mode   */
115            startup_addr /* vector          */
116        ).words[0]
117    );
118}
119
120void apic_send_ipi_core(irq_t vector, cpu_id_t cpu_id)
121{
122    apic_icr1_t icr1;
123    /* wait till we can send an IPI */
124    do {
125        icr1.words[0] = apic_read_reg(APIC_ICR1);
126    } while (apic_icr1_get_delivery_status(icr1));
127
128    apic_write_icr(
129        apic_icr2_new(
130            cpu_id      /* dest */
131        ).words[0],
132        apic_icr1_new(
133            0,          /* dest_shorthand  */
134            0,          /* trigger_mode    */
135            0,          /* level           */
136            0,          /* delivery_status */
137            0,          /* dest_mode       */
138            0,          /* delivery_mode   */
139            vector      /* vector          */
140        ).words[0]
141    );
142}
143
144void apic_send_ipi_cluster(irq_t vector, word_t mda)
145{
146    apic_icr1_t icr1;
147    /* wait till we can send an IPI */
148    do {
149        icr1.words[0] = apic_read_reg(APIC_ICR1);
150    } while (apic_icr1_get_delivery_status(icr1));
151
152    apic_write_icr(
153        apic_icr2_new(
154            mda         /* message destination address */
155        ).words[0],
156        apic_icr1_new(
157            0,          /* dest_shorthand  */
158            0,          /* trigger_mode    */
159            0,          /* level           */
160            0,          /* delivery_status */
161            1,          /* dest_mode       */
162            0,          /* delivery_mode   */
163            vector      /* vector          */
164        ).words[0]
165    );
166}
167#endif /* CONFIG_XAPIC */
168