]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/x86/xen/pvcpu_enum.c
MFV r282150
[FreeBSD/FreeBSD.git] / sys / x86 / xen / pvcpu_enum.c
1 /*-
2  * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org>
3  * Copyright (c) 2013 Roger Pau MonnĂ© <roger.pau@citrix.com>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/bus.h>
34 #include <sys/kernel.h>
35 #include <sys/smp.h>
36 #include <sys/pcpu.h>
37 #include <vm/vm.h>
38 #include <vm/pmap.h>
39
40 #include <machine/intr_machdep.h>
41 #include <x86/apicvar.h>
42
43 #include <machine/cpu.h>
44 #include <machine/smp.h>
45
46 #include <xen/xen-os.h>
47 #include <xen/xen_intr.h>
48 #include <xen/hypervisor.h>
49
50 #include <xen/interface/vcpu.h>
51
52 #include <contrib/dev/acpica/include/acpi.h>
53 #include <contrib/dev/acpica/include/actables.h>
54
55 #include <dev/acpica/acpivar.h>
56
57 static int xenpv_probe(void);
58 static int xenpv_probe_cpus(void);
59 static int xenpv_setup_local(void);
60 static int xenpv_setup_io(void);
61
62 static ACPI_TABLE_MADT *madt;
63 static vm_paddr_t madt_physaddr;
64 static vm_offset_t madt_length;
65
66 static struct apic_enumerator xenpv_enumerator = {
67         "Xen PV",
68         xenpv_probe,
69         xenpv_probe_cpus,
70         xenpv_setup_local,
71         xenpv_setup_io
72 };
73
74 /*--------------------- Helper functions to parse MADT -----------------------*/
75
76 /*
77  * Parse an interrupt source override for an ISA interrupt.
78  */
79 static void
80 madt_parse_interrupt_override(ACPI_MADT_INTERRUPT_OVERRIDE *intr)
81 {
82         enum intr_trigger trig;
83         enum intr_polarity pol;
84         int ret;
85
86         if (acpi_quirks & ACPI_Q_MADT_IRQ0 && intr->SourceIrq == 0 &&
87             intr->GlobalIrq == 2) {
88                 if (bootverbose)
89                         printf("MADT: Skipping timer override\n");
90                 return;
91         }
92
93         madt_parse_interrupt_values(intr, &trig, &pol);
94
95         /* Remap the IRQ if it is mapped to a different interrupt vector. */
96         if (intr->SourceIrq != intr->GlobalIrq && intr->GlobalIrq > 15 &&
97             intr->SourceIrq == AcpiGbl_FADT.SciInterrupt)
98                 /*
99                  * If the SCI is remapped to a non-ISA global interrupt,
100                  * then override the vector we use to setup.
101                  */
102                 acpi_OverrideInterruptLevel(intr->GlobalIrq);
103
104         /* Register the IRQ with the polarity and trigger mode found. */
105         ret = xen_register_pirq(intr->GlobalIrq, trig, pol);
106         if (ret != 0)
107                 panic("Unable to register interrupt override");
108 }
109
110 /*
111  * Call the handler routine for each entry in the MADT table.
112  */
113 static void
114 madt_walk_table(acpi_subtable_handler *handler, void *arg)
115 {
116
117         acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
118             handler, arg);
119 }
120
121 /*
122  * Parse interrupt entries.
123  */
124 static void
125 madt_parse_ints(ACPI_SUBTABLE_HEADER *entry, void *arg __unused)
126 {
127
128         if (entry->Type == ACPI_MADT_TYPE_INTERRUPT_OVERRIDE)
129                 madt_parse_interrupt_override(
130                     (ACPI_MADT_INTERRUPT_OVERRIDE *)entry);
131 }
132
133 /*---------------------------- Xen PV enumerator -----------------------------*/
134
135 /*
136  * This enumerator will only be registered on PVH
137  */
138 static int
139 xenpv_probe(void)
140 {
141         return (0);
142 }
143
144 /*
145  * Test each possible vCPU in order to find the number of vCPUs
146  */
147 static int
148 xenpv_probe_cpus(void)
149 {
150 #ifdef SMP
151         int i, ret;
152
153         for (i = 0; i < MAXCPU; i++) {
154                 ret = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL);
155                 if (ret >= 0)
156                         lapic_create((i * 2), (i == 0));
157         }
158 #endif
159         return (0);
160 }
161
162 /*
163  * Initialize the vCPU id of the BSP
164  */
165 static int
166 xenpv_setup_local(void)
167 {
168         PCPU_SET(vcpu_id, 0);
169         lapic_init(0);
170         return (0);
171 }
172
173 /*
174  * On PVH guests there's no IO APIC
175  */
176 static int
177 xenpv_setup_io(void)
178 {
179
180         if (xen_initial_domain()) {
181                 int i, ret;
182
183                 /* Map MADT */
184                 madt_physaddr = acpi_find_table(ACPI_SIG_MADT);
185                 madt = acpi_map_table(madt_physaddr, ACPI_SIG_MADT);
186                 madt_length = madt->Header.Length;
187
188                 /* Try to initialize ACPI so that we can access the FADT. */
189                 i = acpi_Startup();
190                 if (ACPI_FAILURE(i)) {
191                         printf("MADT: ACPI Startup failed with %s\n",
192                             AcpiFormatException(i));
193                         printf("Try disabling either ACPI or apic support.\n");
194                         panic("Using MADT but ACPI doesn't work");
195                 }
196
197                 /* Run through the table to see if there are any overrides. */
198                 madt_walk_table(madt_parse_ints, NULL);
199
200                 /*
201                  * If there was not an explicit override entry for the SCI,
202                  * force it to use level trigger and active-low polarity.
203                  */
204                 if (!madt_found_sci_override) {
205                         printf(
206         "MADT: Forcing active-low polarity and level trigger for SCI\n");
207                         ret = xen_register_pirq(AcpiGbl_FADT.SciInterrupt,
208                             INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
209                         if (ret != 0)
210                                 panic("Unable to register SCI IRQ");
211                 }
212
213                 /* Register legacy ISA IRQs */
214                 for (i = 1; i < 16; i++) {
215                         if (intr_lookup_source(i) != NULL)
216                                 continue;
217                         ret = xen_register_pirq(i, INTR_TRIGGER_EDGE,
218                             INTR_POLARITY_LOW);
219                         if (ret != 0 && bootverbose)
220                                 printf("Unable to register legacy IRQ#%d: %d\n",
221                                     i, ret);
222                 }
223
224                 acpi_SetDefaultIntrModel(ACPI_INTR_APIC);
225         }
226         return (0);
227 }
228
229 static void
230 xenpv_register(void *dummy __unused)
231 {
232         if (xen_pv_domain()) {
233                 apic_register_enumerator(&xenpv_enumerator);
234         }
235 }
236 SYSINIT(xenpv_register, SI_SUB_TUNABLES - 1, SI_ORDER_FIRST, xenpv_register, NULL);
237
238 /*
239  * Setup per-CPU vCPU IDs
240  */
241 static void
242 xenpv_set_ids(void *dummy)
243 {
244         struct pcpu *pc;
245         int i;
246
247         CPU_FOREACH(i) {
248                 pc = pcpu_find(i);
249                 pc->pc_vcpu_id = i;
250         }
251 }
252 SYSINIT(xenpv_set_ids, SI_SUB_CPU, SI_ORDER_MIDDLE, xenpv_set_ids, NULL);