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