pvcpu_enum.c 6.8 KB

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