acpimadt.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. /* $OpenBSD: acpimadt.c,v 1.32 2015/06/26 18:12:23 guenther Exp $ */
  2. /*
  3. * Copyright (c) 2006 Mark Kettenis <kettenis@openbsd.org>
  4. *
  5. * Permission to use, copy, modify, and distribute this software for any
  6. * purpose with or without fee is hereby granted, provided that the above
  7. * copyright notice and this permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. */
  17. #include <sys/param.h>
  18. #include <sys/systm.h>
  19. #include <sys/device.h>
  20. #include <sys/malloc.h>
  21. #include <machine/apicvar.h>
  22. #include <machine/cpuvar.h>
  23. #include <machine/bus.h>
  24. #include <dev/acpi/acpireg.h>
  25. #include <dev/acpi/acpivar.h>
  26. #include <dev/acpi/acpidev.h>
  27. #include <dev/acpi/amltypes.h>
  28. #include <dev/acpi/dsdt.h>
  29. #include <machine/i8259.h>
  30. #include <machine/i82093reg.h>
  31. #include <machine/i82093var.h>
  32. #include <machine/i82489reg.h>
  33. #include <machine/i82489var.h>
  34. #include <machine/mpbiosvar.h>
  35. #include "ioapic.h"
  36. u_int8_t acpi_lapic_flags[LAPIC_MAP_SIZE];
  37. int acpimadt_match(struct device *, void *, void *);
  38. void acpimadt_attach(struct device *, struct device *, void *);
  39. struct cfattach acpimadt_ca = {
  40. sizeof(struct device), acpimadt_match, acpimadt_attach
  41. };
  42. struct cfdriver acpimadt_cd = {
  43. NULL, "acpimadt", DV_DULL
  44. };
  45. int acpimadt_validate(struct acpi_madt *);
  46. int acpimadt_cfg_intr(int, u_int32_t *);
  47. int acpimadt_print(void *, const char *);
  48. int
  49. acpimadt_match(struct device *parent, void *match, void *aux)
  50. {
  51. struct acpi_attach_args *aaa = aux;
  52. struct acpi_table_header *hdr;
  53. /*
  54. * If we do not have a table, it is not us
  55. */
  56. if (aaa->aaa_table == NULL)
  57. return (0);
  58. /*
  59. * If it is an MADT table, we can attach
  60. */
  61. hdr = (struct acpi_table_header *)aaa->aaa_table;
  62. if (memcmp(hdr->signature, MADT_SIG, sizeof(MADT_SIG) - 1) != 0)
  63. return (0);
  64. return (1);
  65. }
  66. int
  67. acpimadt_validate(struct acpi_madt *madt)
  68. {
  69. caddr_t addr = (caddr_t)(madt + 1);
  70. while (addr < (caddr_t)madt + madt->hdr.length) {
  71. union acpi_madt_entry *entry = (union acpi_madt_entry *)addr;
  72. u_int8_t length = entry->madt_lapic.length;
  73. if (length < 2)
  74. return (0);
  75. if (addr + length > (caddr_t)madt + madt->hdr.length)
  76. return (0);
  77. switch (entry->madt_lapic.apic_type) {
  78. case ACPI_MADT_LAPIC:
  79. if (length != sizeof(entry->madt_lapic))
  80. return (0);
  81. break;
  82. case ACPI_MADT_IOAPIC:
  83. if (length != sizeof(entry->madt_ioapic))
  84. return (0);
  85. break;
  86. case ACPI_MADT_OVERRIDE:
  87. if (length != sizeof(entry->madt_override))
  88. return (0);
  89. break;
  90. case ACPI_MADT_NMI:
  91. if (length != sizeof(entry->madt_nmi))
  92. return (0);
  93. break;
  94. case ACPI_MADT_LAPIC_NMI:
  95. if (length != sizeof(entry->madt_lapic_nmi))
  96. return (0);
  97. break;
  98. case ACPI_MADT_LAPIC_OVERRIDE:
  99. if (length != sizeof(entry->madt_lapic_override))
  100. return (0);
  101. break;
  102. case ACPI_MADT_IO_SAPIC:
  103. if (length != sizeof(entry->madt_io_sapic))
  104. return (0);
  105. break;
  106. case ACPI_MADT_LOCAL_SAPIC:
  107. if (length != sizeof(entry->madt_local_sapic))
  108. return (0);
  109. break;
  110. case ACPI_MADT_PLATFORM_INT:
  111. if (length != sizeof(entry->madt_platform_int))
  112. return (0);
  113. break;
  114. case ACPI_MADT_X2APIC:
  115. if (length != sizeof(entry->madt_x2apic))
  116. return (0);
  117. break;
  118. case ACPI_MADT_X2APIC_NMI:
  119. if (length != sizeof(entry->madt_x2apic_nmi))
  120. return (0);
  121. break;
  122. }
  123. addr += length;
  124. }
  125. return (1);
  126. }
  127. struct mp_bus acpimadt_busses[256];
  128. struct mp_bus acpimadt_isa_bus;
  129. int
  130. acpimadt_cfg_intr(int flags, u_int32_t *redir)
  131. {
  132. int mpspo = (flags >> MPS_INTPO_SHIFT) & MPS_INTPO_MASK;
  133. int mpstrig = (flags >> MPS_INTTR_SHIFT) & MPS_INTTR_MASK;
  134. *redir &= ~IOAPIC_REDLO_DEL_MASK;
  135. switch (mpspo) {
  136. case MPS_INTPO_DEF:
  137. case MPS_INTPO_ACTHI:
  138. *redir &= ~IOAPIC_REDLO_ACTLO;
  139. break;
  140. case MPS_INTPO_ACTLO:
  141. *redir |= IOAPIC_REDLO_ACTLO;
  142. break;
  143. default:
  144. return (0);
  145. }
  146. *redir |= (IOAPIC_REDLO_DEL_LOPRI << IOAPIC_REDLO_DEL_SHIFT);
  147. switch (mpstrig) {
  148. case MPS_INTTR_LEVEL:
  149. *redir |= IOAPIC_REDLO_LEVEL;
  150. break;
  151. case MPS_INTTR_DEF:
  152. case MPS_INTTR_EDGE:
  153. *redir &= ~IOAPIC_REDLO_LEVEL;
  154. break;
  155. default:
  156. return (0);
  157. }
  158. return (1);
  159. }
  160. static u_int8_t lapic_map[256];
  161. void
  162. acpimadt_attach(struct device *parent, struct device *self, void *aux)
  163. {
  164. struct acpi_softc *acpi_sc = (struct acpi_softc *)parent;
  165. struct device *mainbus = parent->dv_parent->dv_parent;
  166. struct acpi_attach_args *aaa = aux;
  167. struct acpi_madt *madt = (struct acpi_madt *)aaa->aaa_table;
  168. caddr_t addr = (caddr_t)(madt + 1);
  169. struct aml_value arg;
  170. struct mp_intr_map *map;
  171. struct ioapic_softc *apic;
  172. int nlapic_nmis = 0;
  173. int pin;
  174. /* Do some sanity checks before committing to run in APIC mode. */
  175. if (!acpimadt_validate(madt)) {
  176. printf(": invalid, skipping\n");
  177. return;
  178. }
  179. printf(" addr 0x%x", madt->local_apic_address);
  180. if (madt->flags & ACPI_APIC_PCAT_COMPAT)
  181. printf(": PC-AT compat");
  182. printf("\n");
  183. /* Tell the BIOS we will be using APIC mode. */
  184. memset(&arg, 0, sizeof(arg));
  185. arg.type = AML_OBJTYPE_INTEGER;
  186. arg.v_integer = 1;
  187. aml_evalname(acpi_sc, NULL, "\\_PIC", 1, &arg, NULL);
  188. mp_busses = acpimadt_busses;
  189. mp_nbusses = nitems(acpimadt_busses);
  190. mp_isa_bus = &acpimadt_isa_bus;
  191. lapic_boot_init(madt->local_apic_address);
  192. /* 1st pass, get CPUs and IOAPICs */
  193. while (addr < (caddr_t)madt + madt->hdr.length) {
  194. union acpi_madt_entry *entry = (union acpi_madt_entry *)addr;
  195. struct cpu_attach_args caa;
  196. struct apic_attach_args aaa;
  197. switch (entry->madt_lapic.apic_type) {
  198. case ACPI_MADT_LAPIC:
  199. dprintf("%s: LAPIC: acpi_proc_id %x, apic_id %x, flags 0x%x\n",
  200. self->dv_xname, entry->madt_lapic.acpi_proc_id,
  201. entry->madt_lapic.apic_id,
  202. entry->madt_lapic.flags);
  203. if ((entry->madt_lapic.flags & ACPI_PROC_ENABLE) == 0)
  204. break;
  205. lapic_map[entry->madt_lapic.acpi_proc_id] =
  206. entry->madt_lapic.apic_id;
  207. acpi_lapic_flags[entry->madt_lapic.acpi_proc_id] =
  208. entry->madt_lapic.flags;
  209. memset(&caa, 0, sizeof(struct cpu_attach_args));
  210. if (lapic_cpu_number() == entry->madt_lapic.apic_id)
  211. caa.cpu_role = CPU_ROLE_BP;
  212. else {
  213. caa.cpu_role = CPU_ROLE_AP;
  214. ncpusfound++;
  215. }
  216. caa.caa_name = "cpu";
  217. caa.cpu_number = entry->madt_lapic.apic_id;
  218. #ifdef MULTIPROCESSOR
  219. caa.cpu_func = &mp_cpu_funcs;
  220. #endif
  221. #ifdef __i386__
  222. /*
  223. * XXX utterly wrong. These are the
  224. * cpu_feature/cpu_id from the BSP cpu, now
  225. * being given to another cpu. This is
  226. * bullshit.
  227. */
  228. extern int cpu_id, cpu_feature;
  229. caa.cpu_signature = cpu_id;
  230. caa.feature_flags = cpu_feature;
  231. #endif
  232. config_found(mainbus, &caa, acpimadt_print);
  233. break;
  234. case ACPI_MADT_IOAPIC:
  235. dprintf("%s: IOAPIC: acpi_ioapic_id %x, address 0x%x, global_int_base 0x%x\n",
  236. self->dv_xname, entry->madt_ioapic.acpi_ioapic_id,
  237. entry->madt_ioapic.address,
  238. entry->madt_ioapic.global_int_base);
  239. memset(&aaa, 0, sizeof(struct apic_attach_args));
  240. aaa.aaa_name = "ioapic";
  241. aaa.apic_id = entry->madt_ioapic.acpi_ioapic_id;
  242. aaa.apic_address = entry->madt_ioapic.address;
  243. aaa.apic_vecbase = entry->madt_ioapic.global_int_base;
  244. config_found(mainbus, &aaa, acpimadt_print);
  245. break;
  246. case ACPI_MADT_LAPIC_NMI:
  247. nlapic_nmis++;
  248. break;
  249. }
  250. addr += entry->madt_lapic.length;
  251. }
  252. mp_intrs = mallocarray(nlapic_nmis, sizeof(struct mp_intr_map),
  253. M_DEVBUF, M_NOWAIT);
  254. if (mp_intrs == NULL)
  255. return;
  256. /* 2nd pass, get interrupt overrides */
  257. addr = (caddr_t)(madt + 1);
  258. while (addr < (caddr_t)madt + madt->hdr.length) {
  259. union acpi_madt_entry *entry = (union acpi_madt_entry *)addr;
  260. switch (entry->madt_lapic.apic_type) {
  261. case ACPI_MADT_LAPIC:
  262. case ACPI_MADT_IOAPIC:
  263. break;
  264. case ACPI_MADT_OVERRIDE:
  265. dprintf("%s: OVERRIDE: bus %x, source %x, global_int %x, flags %x\n",
  266. self->dv_xname, entry->madt_override.bus,
  267. entry->madt_override.source,
  268. entry->madt_override.global_int,
  269. entry->madt_override.flags);
  270. pin = entry->madt_override.global_int;
  271. apic = ioapic_find_bybase(pin);
  272. map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT | M_ZERO);
  273. if (map == NULL)
  274. return;
  275. map->ioapic = apic;
  276. map->ioapic_pin = pin - apic->sc_apic_vecbase;
  277. map->bus_pin = entry->madt_override.source;
  278. map->flags = entry->madt_override.flags;
  279. if (!acpimadt_cfg_intr(entry->madt_override.flags, &map->redir)) {
  280. printf("%s: bogus override for pin %d\n",
  281. self->dv_xname, pin);
  282. free(map, M_DEVBUF, 0);
  283. break;
  284. }
  285. map->ioapic_ih = APIC_INT_VIA_APIC |
  286. ((apic->sc_apicid << APIC_INT_APIC_SHIFT) |
  287. (pin << APIC_INT_PIN_SHIFT));
  288. apic->sc_pins[pin].ip_map = map;
  289. map->next = mp_isa_bus->mb_intrs;
  290. mp_isa_bus->mb_intrs = map;
  291. break;
  292. case ACPI_MADT_LAPIC_NMI:
  293. dprintf("%s: LAPIC_NMI: acpi_proc_id %x, local_apic_lint %x, flags %x\n",
  294. self->dv_xname, entry->madt_lapic_nmi.acpi_proc_id,
  295. entry->madt_lapic_nmi.local_apic_lint,
  296. entry->madt_lapic_nmi.flags);
  297. pin = entry->madt_lapic_nmi.local_apic_lint;
  298. map = &mp_intrs[mp_nintrs++];
  299. memset(map, 0, sizeof *map);
  300. map->cpu_id = lapic_map[entry->madt_lapic_nmi.acpi_proc_id];
  301. map->ioapic_pin = pin;
  302. map->flags = entry->madt_lapic_nmi.flags;
  303. if ((pin != 0 && pin != 1) ||
  304. !acpimadt_cfg_intr(entry->madt_lapic_nmi.flags, &map->redir)) {
  305. printf("%s: bogus nmi for apid %d\n",
  306. self->dv_xname, map->cpu_id);
  307. mp_nintrs--;
  308. break;
  309. }
  310. map->redir &= ~IOAPIC_REDLO_DEL_MASK;
  311. map->redir |= (IOAPIC_REDLO_DEL_NMI << IOAPIC_REDLO_DEL_SHIFT);
  312. break;
  313. case ACPI_MADT_X2APIC:
  314. case ACPI_MADT_X2APIC_NMI:
  315. break;
  316. default:
  317. printf("%s: unknown apic structure type %x\n",
  318. self->dv_xname, entry->madt_lapic.apic_type);
  319. }
  320. addr += entry->madt_lapic.length;
  321. }
  322. /*
  323. * ISA interrupts are supposed to be identity mapped unless
  324. * there is an override, in which case we will already have a
  325. * mapping for the interrupt.
  326. */
  327. for (pin = 0; pin < ICU_LEN; pin++) {
  328. /* Skip if we already have a mapping for this interrupt. */
  329. for (map = mp_isa_bus->mb_intrs; map != NULL; map = map->next)
  330. if (map->bus_pin == pin)
  331. break;
  332. if (map != NULL)
  333. continue;
  334. apic = ioapic_find_bybase(pin);
  335. map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT | M_ZERO);
  336. if (map == NULL)
  337. return;
  338. map->ioapic = apic;
  339. map->ioapic_pin = pin;
  340. map->bus_pin = pin;
  341. map->redir = (IOAPIC_REDLO_DEL_LOPRI << IOAPIC_REDLO_DEL_SHIFT);
  342. map->ioapic_ih = APIC_INT_VIA_APIC |
  343. ((apic->sc_apicid << APIC_INT_APIC_SHIFT) |
  344. (pin << APIC_INT_PIN_SHIFT));
  345. apic->sc_pins[pin].ip_map = map;
  346. map->next = mp_isa_bus->mb_intrs;
  347. mp_isa_bus->mb_intrs = map;
  348. }
  349. }
  350. int
  351. acpimadt_print(void *aux, const char *pnp)
  352. {
  353. struct apic_attach_args *aaa = aux;
  354. if (pnp)
  355. printf("%s at %s:", aaa->aaa_name, pnp);
  356. return (UNCONF);
  357. }