static boolean_t acpi_sci_test(const struct acpi_sci_mode *mode) { void *sci_desc; long last_cnt; FADT_VPRINTF("SCI testing %s/%s\n", intr_str_trigger(mode->sci_trig), intr_str_polarity(mode->sci_pola)); last_cnt = get_interrupt_counter(acpi_sci_irq, 0); machintr_legacy_intr_config(acpi_sci_irq, mode->sci_trig, mode->sci_pola); sci_desc = register_int(acpi_sci_irq, acpi_sci_dummy_intr, NULL, "sci", NULL, INTR_EXCL | INTR_CLOCK | INTR_NOPOLL | INTR_MPSAFE | INTR_NOENTROPY, 0); DELAY(100 * 1000); unregister_int(sci_desc, 0); if (get_interrupt_counter(acpi_sci_irq, 0) - last_cnt < 20) { acpi_sci_trig = mode->sci_trig; acpi_sci_pola = mode->sci_pola; kprintf("ACPI FADT: SCI select %s/%s\n", intr_str_trigger(acpi_sci_trig), intr_str_polarity(acpi_sci_pola)); return TRUE; } return FALSE; }
void acpi_sci_config(void) { const struct acpi_sci_mode *mode; KKASSERT(mycpuid == 0); if (acpi_sci_irq < 0) return; if (acpi_sci_trig != INTR_TRIGGER_CONFORM) { KKASSERT(acpi_sci_pola != INTR_POLARITY_CONFORM); machintr_legacy_intr_config(acpi_sci_irq, acpi_sci_trig, acpi_sci_pola); return; } kprintf("ACPI FADT: SCI testing interrupt mode ...\n"); for (mode = acpi_sci_modes; mode->sci_trig != INTR_TRIGGER_CONFORM; ++mode) { void *sci_desc; long last_cnt; FADT_VPRINTF("SCI testing %s/%s\n", intr_str_trigger(mode->sci_trig), intr_str_polarity(mode->sci_pola)); last_cnt = get_interrupt_counter(acpi_sci_irq, 0); machintr_legacy_intr_config(acpi_sci_irq, mode->sci_trig, mode->sci_pola); sci_desc = register_int(acpi_sci_irq, acpi_sci_dummy_intr, NULL, "sci", NULL, INTR_EXCL | INTR_CLOCK | INTR_NOPOLL | INTR_MPSAFE | INTR_NOENTROPY, 0); DELAY(100 * 1000); unregister_int(sci_desc, 0); if (get_interrupt_counter(acpi_sci_irq, 0) - last_cnt < 20) { acpi_sci_trig = mode->sci_trig; acpi_sci_pola = mode->sci_pola; kprintf("ACPI FADT: SCI select %s/%s\n", intr_str_trigger(acpi_sci_trig), intr_str_polarity(acpi_sci_pola)); return; } } kprintf("ACPI FADT: no suitable interrupt mode for SCI, disable\n"); acpi_sci_irq = -1; }
void ioapic_set_legacy_irqmap(int irq, int gsi, enum intr_trigger trig, enum intr_polarity pola) { struct ioapic_irqinfo *info; struct ioapic_irqmap *map; void *ioaddr; int pin, cpuid; KKASSERT(trig == INTR_TRIGGER_EDGE || trig == INTR_TRIGGER_LEVEL); KKASSERT(pola == INTR_POLARITY_HIGH || pola == INTR_POLARITY_LOW); KKASSERT(irq >= 0 && irq < IOAPIC_HWI_VECTORS); if (irq > ioapic_abi_legacy_irq_max) ioapic_abi_legacy_irq_max = irq; cpuid = ioapic_abi_gsi_cpuid(irq, gsi); map = &ioapic_irqmaps[cpuid][irq]; KKASSERT(map->im_type == IOAPIC_IMT_UNUSED); map->im_type = IOAPIC_IMT_LEGACY; map->im_gsi = gsi; map->im_trig = trig; map->im_pola = pola; if (bootverbose) { kprintf("IOAPIC: irq %d -> gsi %d %s/%s\n", irq, map->im_gsi, intr_str_trigger(map->im_trig), intr_str_polarity(map->im_pola)); } pin = ioapic_gsi_pin(map->im_gsi); ioaddr = ioapic_gsi_ioaddr(map->im_gsi); info = &ioapic_irqs[irq]; imen_lock(); info->io_addr = ioaddr; info->io_idx = IOAPIC_REDTBL + (2 * pin); info->io_flags = IOAPIC_IRQI_FLAG_MASKED; if (map->im_trig == INTR_TRIGGER_LEVEL) info->io_flags |= IOAPIC_IRQI_FLAG_LEVEL; ioapic_pin_setup(ioaddr, pin, IDT_OFFSET + irq, map->im_trig, map->im_pola, cpuid); imen_unlock(); }
static void fadt_probe(void) { struct acpi_fadt *fadt; vm_paddr_t fadt_paddr; enum intr_trigger trig; enum intr_polarity pola; int enabled = 1; char *env; fadt_paddr = sdt_search(ACPI_FADT_SIG); if (fadt_paddr == 0) { kprintf("fadt_probe: can't locate FADT\n"); return; } fadt = sdt_sdth_map(fadt_paddr); KKASSERT(fadt != NULL); /* * FADT in ACPI specification 1.0 - 4.0 */ if (fadt->fadt_hdr.sdth_rev < 1 || fadt->fadt_hdr.sdth_rev > 4) { kprintf("fadt_probe: unsupported FADT revision %d\n", fadt->fadt_hdr.sdth_rev); goto back; } if (fadt->fadt_hdr.sdth_len < sizeof(*fadt)) { kprintf("fadt_probe: invalid FADT length %u\n", fadt->fadt_hdr.sdth_len); goto back; } kgetenv_int("hw.acpi.sci.enabled", &enabled); if (!enabled) goto back; acpi_sci_irq = fadt->fadt_sci_int; env = kgetenv("hw.acpi.sci.trigger"); if (env == NULL) goto back; trig = INTR_TRIGGER_CONFORM; if (strcmp(env, "edge") == 0) trig = INTR_TRIGGER_EDGE; else if (strcmp(env, "level") == 0) trig = INTR_TRIGGER_LEVEL; kfreeenv(env); if (trig == INTR_TRIGGER_CONFORM) goto back; env = kgetenv("hw.acpi.sci.polarity"); if (env == NULL) goto back; pola = INTR_POLARITY_CONFORM; if (strcmp(env, "high") == 0) pola = INTR_POLARITY_HIGH; else if (strcmp(env, "low") == 0) pola = INTR_POLARITY_LOW; kfreeenv(env); if (pola == INTR_POLARITY_CONFORM) goto back; acpi_sci_trig = trig; acpi_sci_pola = pola; back: if (acpi_sci_irq >= 0) { FADT_VPRINTF("SCI irq %d, %s/%s\n", acpi_sci_irq, intr_str_trigger(acpi_sci_trig), intr_str_polarity(acpi_sci_pola)); } else { FADT_VPRINTF("SCI is disabled\n"); } sdt_sdth_unmap(&fadt->fadt_hdr); }
int ioapic_conf_legacy_extint(int irq) { struct ioapic_irqinfo *info; struct ioapic_irqmap *map; void *ioaddr; int pin, error, vec; /* XXX only irq0 is allowed */ KKASSERT(irq == 0); vec = IDT_OFFSET + irq; if (ioapic_abi_extint_irq == irq) return 0; else if (ioapic_abi_extint_irq >= 0) return EEXIST; error = icu_ioapic_extint(irq, vec); if (error) return error; /* ExtINT is always targeted to cpu0 */ map = &ioapic_irqmaps[0][irq]; KKASSERT(map->im_type == IOAPIC_IMT_RESERVED || map->im_type == IOAPIC_IMT_LEGACY); if (map->im_type == IOAPIC_IMT_LEGACY) { if (map->im_flags & IOAPIC_IMF_CONF) return EEXIST; } ioapic_abi_extint_irq = irq; map->im_type = IOAPIC_IMT_LEGACY; map->im_trig = INTR_TRIGGER_EDGE; map->im_pola = INTR_POLARITY_HIGH; map->im_flags = IOAPIC_IMF_CONF; map->im_gsi = ioapic_extpin_gsi(); KKASSERT(map->im_gsi >= 0); if (bootverbose) { kprintf("IOAPIC: irq %d -> extint gsi %d %s/%s\n", irq, map->im_gsi, intr_str_trigger(map->im_trig), intr_str_polarity(map->im_pola)); } pin = ioapic_gsi_pin(map->im_gsi); ioaddr = ioapic_gsi_ioaddr(map->im_gsi); info = &ioapic_irqs[irq]; imen_lock(); info->io_addr = ioaddr; info->io_idx = IOAPIC_REDTBL + (2 * pin); info->io_flags = IOAPIC_IRQI_FLAG_MASKED; ioapic_extpin_setup(ioaddr, pin, vec); imen_unlock(); return 0; }
static void ioapic_abi_legacy_intr_config(int irq, enum intr_trigger trig, enum intr_polarity pola) { struct ioapic_irqinfo *info; struct ioapic_irqmap *map = NULL; void *ioaddr; int pin, cpuid; KKASSERT(trig == INTR_TRIGGER_EDGE || trig == INTR_TRIGGER_LEVEL); KKASSERT(pola == INTR_POLARITY_HIGH || pola == INTR_POLARITY_LOW); KKASSERT(irq >= 0 && irq < ioapic_abi_legacy_irq_max); for (cpuid = 0; cpuid < ncpus; ++cpuid) { map = &ioapic_irqmaps[cpuid][irq]; if (map->im_type == IOAPIC_IMT_LEGACY) break; } KKASSERT(cpuid < ncpus); #ifdef notyet if (map->im_flags & IOAPIC_IMF_CONF) { if (trig != map->im_trig) { panic("ioapic_intr_config: trig %s -> %s\n", intr_str_trigger(map->im_trig), intr_str_trigger(trig)); } if (pola != map->im_pola) { panic("ioapic_intr_config: pola %s -> %s\n", intr_str_polarity(map->im_pola), intr_str_polarity(pola)); } return; } #endif map->im_flags |= IOAPIC_IMF_CONF; if (trig == map->im_trig && pola == map->im_pola) return; if (bootverbose) { kprintf("IOAPIC: irq %d, gsi %d %s/%s -> %s/%s\n", irq, map->im_gsi, intr_str_trigger(map->im_trig), intr_str_polarity(map->im_pola), intr_str_trigger(trig), intr_str_polarity(pola)); } map->im_trig = trig; map->im_pola = pola; pin = ioapic_gsi_pin(map->im_gsi); ioaddr = ioapic_gsi_ioaddr(map->im_gsi); info = &ioapic_irqs[irq]; imen_lock(); info->io_flags &= ~IOAPIC_IRQI_FLAG_LEVEL; if (map->im_trig == INTR_TRIGGER_LEVEL) info->io_flags |= IOAPIC_IRQI_FLAG_LEVEL; ioapic_pin_setup(ioaddr, pin, IDT_OFFSET + irq, map->im_trig, map->im_pola, cpuid); imen_unlock(); }
void ioapic_set_legacy_irqmap(int irq, int gsi, enum intr_trigger trig, enum intr_polarity pola) { struct ioapic_irqinfo *info; struct ioapic_irqmap *map; void *ioaddr; int pin, cpuid; KKASSERT(trig == INTR_TRIGGER_EDGE || trig == INTR_TRIGGER_LEVEL); KKASSERT(pola == INTR_POLARITY_HIGH || pola == INTR_POLARITY_LOW); KKASSERT(irq >= 0); if (irq >= IOAPIC_HWI_VECTORS) { /* * Some BIOSes seem to assume that all 256 IDT vectors * could be used, while we limit the available IDT * vectors to 192; find an unused IRQ for this GSI. */ irq = ioapic_find_unused_irqmap(gsi); if (irq < 0) { kprintf("failed to find unused irq for gsi %d, " "overflow\n", gsi); return; } } KKASSERT(irq < IOAPIC_HWI_VECTORS); cpuid = ioapic_abi_gsi_cpuid(irq, gsi); map = &ioapic_irqmaps[cpuid][irq]; if (map->im_type != IOAPIC_IMT_UNUSED) { /* * There are so many IOAPICs, that 1:1 mapping * of GSI and IRQ hits SYSCALL entry. */ irq = ioapic_find_unused_irqmap(gsi); if (irq < 0) { kprintf("failed to find unused irq for gsi %d, " "conflict\n", gsi); return; } KKASSERT(irq < IOAPIC_HWI_VECTORS); cpuid = ioapic_abi_gsi_cpuid(irq, gsi); map = &ioapic_irqmaps[cpuid][irq]; } if (irq > ioapic_abi_legacy_irq_max) ioapic_abi_legacy_irq_max = irq; KKASSERT(map->im_type == IOAPIC_IMT_UNUSED); map->im_type = IOAPIC_IMT_LEGACY; map->im_gsi = gsi; map->im_trig = trig; map->im_pola = pola; if (bootverbose) { kprintf("IOAPIC: irq %d -> gsi %d %s/%s\n", irq, map->im_gsi, intr_str_trigger(map->im_trig), intr_str_polarity(map->im_pola)); } pin = ioapic_gsi_pin(map->im_gsi); ioaddr = ioapic_gsi_ioaddr(map->im_gsi); info = &ioapic_irqs[irq]; imen_lock(); info->io_addr = ioaddr; info->io_idx = IOAPIC_REDTBL + (2 * pin); info->io_flags = IOAPIC_IRQI_FLAG_MASKED; if (map->im_trig == INTR_TRIGGER_LEVEL) info->io_flags |= IOAPIC_IRQI_FLAG_LEVEL; ioapic_pin_setup(ioaddr, pin, IDT_OFFSET + irq, map->im_trig, map->im_pola, cpuid); imen_unlock(); }
static void fadt_probe(void) { ACPI_TABLE_FADT *fadt; vm_paddr_t fadt_paddr; enum intr_trigger trig; enum intr_polarity pola; int enabled = 1; char *env; fadt_paddr = sdt_search(ACPI_SIG_FADT); if (fadt_paddr == 0) { kprintf("fadt_probe: can't locate FADT\n"); return; } fadt = sdt_sdth_map(fadt_paddr); KKASSERT(fadt != NULL); /* * FADT in ACPI specification 1.0 - 6.0 */ if (fadt->Header.Revision < 1 || fadt->Header.Revision > 6) { kprintf("fadt_probe: unknown FADT revision %d\n", fadt->Header.Revision); } if (fadt->Header.Length < ACPI_FADT_V1_SIZE) { kprintf("fadt_probe: invalid FADT length %u (< %u)\n", fadt->Header.Length, ACPI_FADT_V1_SIZE); goto back; } kgetenv_int("hw.acpi.sci.enabled", &enabled); if (!enabled) goto back; acpi_sci_irq = fadt->SciInterrupt; env = kgetenv("hw.acpi.sci.trigger"); if (env == NULL) goto back; trig = INTR_TRIGGER_CONFORM; if (strcmp(env, "edge") == 0) trig = INTR_TRIGGER_EDGE; else if (strcmp(env, "level") == 0) trig = INTR_TRIGGER_LEVEL; kfreeenv(env); if (trig == INTR_TRIGGER_CONFORM) goto back; env = kgetenv("hw.acpi.sci.polarity"); if (env == NULL) goto back; pola = INTR_POLARITY_CONFORM; if (strcmp(env, "high") == 0) pola = INTR_POLARITY_HIGH; else if (strcmp(env, "low") == 0) pola = INTR_POLARITY_LOW; kfreeenv(env); if (pola == INTR_POLARITY_CONFORM) goto back; acpi_sci_trig = trig; acpi_sci_pola = pola; back: if (acpi_sci_irq >= 0) { FADT_VPRINTF("SCI irq %d, %s/%s\n", acpi_sci_irq, intr_str_trigger(acpi_sci_trig), intr_str_polarity(acpi_sci_pola)); } else { FADT_VPRINTF("SCI is disabled\n"); } sdt_sdth_unmap(&fadt->Header); }