]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/x86/xen/pvcpu_enum.c
Merge xz 5.2.0.
[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
85         if (acpi_quirks & ACPI_Q_MADT_IRQ0 && intr->SourceIrq == 0 &&
86             intr->GlobalIrq == 2) {
87                 if (bootverbose)
88                         printf("MADT: Skipping timer override\n");
89                 return;
90         }
91
92         madt_parse_interrupt_values(intr, &trig, &pol);
93
94         /* Remap the IRQ if it is mapped to a different interrupt vector. */
95         if (intr->SourceIrq != intr->GlobalIrq && intr->GlobalIrq > 15 &&
96             intr->SourceIrq == AcpiGbl_FADT.SciInterrupt)
97                 /*
98                  * If the SCI is remapped to a non-ISA global interrupt,
99                  * then override the vector we use to setup.
100                  */
101                 acpi_OverrideInterruptLevel(intr->GlobalIrq);
102
103         /* Register the IRQ with the polarity and trigger mode found. */
104         xen_register_pirq(intr->GlobalIrq, trig, pol);
105 }
106
107 /*
108  * Call the handler routine for each entry in the MADT table.
109  */
110 static void
111 madt_walk_table(acpi_subtable_handler *handler, void *arg)
112 {
113
114         acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
115             handler, arg);
116 }
117
118 /*
119  * Parse interrupt entries.
120  */
121 static void
122 madt_parse_ints(ACPI_SUBTABLE_HEADER *entry, void *arg __unused)
123 {
124
125         if (entry->Type == ACPI_MADT_TYPE_INTERRUPT_OVERRIDE)
126                 madt_parse_interrupt_override(
127                     (ACPI_MADT_INTERRUPT_OVERRIDE *)entry);
128 }
129
130 /*---------------------------- Xen PV enumerator -----------------------------*/
131
132 /*
133  * This enumerator will only be registered on PVH
134  */
135 static int
136 xenpv_probe(void)
137 {
138         return (0);
139 }
140
141 /*
142  * Test each possible vCPU in order to find the number of vCPUs
143  */
144 static int
145 xenpv_probe_cpus(void)
146 {
147 #ifdef SMP
148         int i, ret;
149
150         for (i = 0; i < MAXCPU; i++) {
151                 ret = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL);
152                 if (ret >= 0)
153                         lapic_create((i * 2), (i == 0));
154         }
155 #endif
156         return (0);
157 }
158
159 /*
160  * Initialize the vCPU id of the BSP
161  */
162 static int
163 xenpv_setup_local(void)
164 {
165         PCPU_SET(vcpu_id, 0);
166         lapic_init(0);
167         return (0);
168 }
169
170 /*
171  * On PVH guests there's no IO APIC
172  */
173 static int
174 xenpv_setup_io(void)
175 {
176
177         if (xen_initial_domain()) {
178                 int i;
179
180                 /* Map MADT */
181                 madt_physaddr = acpi_find_table(ACPI_SIG_MADT);
182                 madt = acpi_map_table(madt_physaddr, ACPI_SIG_MADT);
183                 madt_length = madt->Header.Length;
184
185                 /* Try to initialize ACPI so that we can access the FADT. */
186                 i = acpi_Startup();
187                 if (ACPI_FAILURE(i)) {
188                         printf("MADT: ACPI Startup failed with %s\n",
189                             AcpiFormatException(i));
190                         printf("Try disabling either ACPI or apic support.\n");
191                         panic("Using MADT but ACPI doesn't work");
192                 }
193
194                 /* Run through the table to see if there are any overrides. */
195                 madt_walk_table(madt_parse_ints, NULL);
196
197                 /*
198                  * If there was not an explicit override entry for the SCI,
199                  * force it to use level trigger and active-low polarity.
200                  */
201                 if (!madt_found_sci_override) {
202                         printf(
203         "MADT: Forcing active-low polarity and level trigger for SCI\n");
204                         xen_register_pirq(AcpiGbl_FADT.SciInterrupt,
205                             INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
206                 }
207
208                 acpi_SetDefaultIntrModel(ACPI_INTR_APIC);
209         }
210         return (0);
211 }
212
213 static void
214 xenpv_register(void *dummy __unused)
215 {
216         if (xen_pv_domain()) {
217                 apic_register_enumerator(&xenpv_enumerator);
218         }
219 }
220 SYSINIT(xenpv_register, SI_SUB_TUNABLES - 1, SI_ORDER_FIRST, xenpv_register, NULL);
221
222 /*
223  * Setup per-CPU vCPU IDs
224  */
225 static void
226 xenpv_set_ids(void *dummy)
227 {
228         struct pcpu *pc;
229         int i;
230
231         CPU_FOREACH(i) {
232                 pc = pcpu_find(i);
233                 pc->pc_vcpu_id = i;
234         }
235 }
236 SYSINIT(xenpv_set_ids, SI_SUB_CPU, SI_ORDER_MIDDLE, xenpv_set_ids, NULL);