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/x2apic.h>
15
16BOOT_CODE bool_t
17x2apic_is_enabled(void)
18{
19    apic_base_msr_t apic_base_msr;
20    apic_base_msr.words[0] = x86_rdmsr_low(IA32_APIC_BASE_MSR);
21
22    if ((x86_cpuid_ecx(1, 0) & BIT(21)) &&
23            apic_base_msr_get_enabled(apic_base_msr) &&
24            apic_base_msr_get_x2apic(apic_base_msr)) {
25        return true;
26    }
27    return false;
28}
29
30#ifdef CONFIG_X2APIC
31BOOT_CODE bool_t
32apic_enable(void)
33{
34    apic_base_msr_t apic_base_msr;
35    apic_base_msr.words[0] = x86_rdmsr_low(IA32_APIC_BASE_MSR);
36
37    if (!apic_base_msr_get_enabled(apic_base_msr)) {
38        printf("APIC: Enabled bit not set\n");
39        return false;
40    }
41
42    if (x86_cpuid_ecx(1, 0) & BIT(21)) {
43        apic_base_msr = apic_base_msr_set_x2apic(apic_base_msr, 1);
44        x86_wrmsr(IA32_APIC_BASE_MSR, apic_base_msr.words[0]);
45    } else {
46        printf("APIC: x2APIC is not supported on this machine\n");
47        return false;
48    }
49
50    return true;
51}
52
53bool_t apic_is_interrupt_pending(void)
54{
55    word_t i;
56
57    assert(int_irq_min % 32 == 0);
58    for (i = int_irq_min; i <= int_irq_max; i += 32) {
59        if (apic_read_reg(APIC_IRR_BASE + ((i / 32) - 1)) != 0) {
60            return true;
61        }
62    }
63    return false;
64}
65
66BOOT_CODE void
67apic_send_init_ipi(cpu_id_t cpu_id)
68{
69    apic_write_icr(
70        x2apic_icr2_new(
71            cpu_id      /* dest */
72        ).words[0],
73        x2apic_icr1_new(
74            0,          /* dest_shorthand  */
75            1,          /* trigger_mode    */
76            1,          /* level           */
77            0,          /* dest_mode       */
78            5,          /* delivery_mode   */
79            0           /* vector          */
80        ).words[0]
81    );
82    apic_write_icr(
83        apic_icr2_new(
84            cpu_id      /* dest */
85        ).words[0],
86        x2apic_icr1_new(
87            0,          /* dest_shorthand  */
88            1,          /* trigger_mode    */
89            0,          /* level           */
90            0,          /* dest_mode       */
91            5,          /* delivery_mode   */
92            0           /* vector          */
93        ).words[0]
94    );
95}
96
97BOOT_CODE void
98apic_send_startup_ipi(cpu_id_t cpu_id, paddr_t startup_addr)
99{
100    /* check if 4K aligned */
101    assert(IS_ALIGNED(startup_addr, PAGE_BITS));
102    /* check if startup_addr < 640K */
103    assert(startup_addr < 0xa0000);
104    startup_addr >>= PAGE_BITS;
105
106    apic_write_icr(
107        x2apic_icr2_new(
108            cpu_id      /* dest */
109        ).words[0],
110        x2apic_icr1_new(
111            0,           /* dest_shorthand  */
112            0,           /* trigger_mode    */
113            0,           /* level           */
114            0,           /* dest_mode       */
115            6,           /* delivery_mode   */
116            startup_addr /* vector          */
117        ).words[0]
118    );
119}
120
121void apic_send_ipi_core(irq_t vector, cpu_id_t cpu_id)
122{
123    apic_write_icr(
124        x2apic_icr2_new(
125            cpu_id      /* dest */
126        ).words[0],
127        x2apic_icr1_new(
128            0,          /* dest_shorthand  */
129            0,          /* trigger_mode    */
130            0,          /* level           */
131            0,          /* dest_mode       */
132            0,          /* delivery_mode   */
133            vector      /* vector          */
134        ).words[0]
135    );
136}
137
138void apic_send_ipi_cluster(irq_t vector, word_t mda)
139{
140    apic_write_icr(
141        x2apic_icr2_new(
142            mda         /* message destination address */
143        ).words[0],
144        x2apic_icr1_new(
145            0,          /* dest_shorthand  */
146            0,          /* trigger_mode    */
147            0,          /* level           */
148            1,          /* dest_mode       */
149            0,          /* delivery_mode   */
150            vector      /* vector          */
151        ).words[0]
152    );
153}
154#endif /* CONFIG_X2APIC */
155