/* * Look for an ECDT and if we find one, set up default GPE and * space handlers to catch attempts to access EC space before * we have a real driver instance in place. * * TODO: Some old Gateway laptops need us to fake up an ECDT or * otherwise attach early so that _REG methods can run. */ void acpi_ec_ecdt_probe(device_t parent) { ACPI_TABLE_ECDT *ecdt; ACPI_STATUS status; device_t child; ACPI_HANDLE h; struct acpi_ec_params *params; ACPI_FUNCTION_TRACE((char *)(uintptr_t)__func__); /* Find and validate the ECDT. */ status = AcpiGetTable(ACPI_SIG_ECDT, 1, (ACPI_TABLE_HEADER **)&ecdt); if (ACPI_FAILURE(status) || ecdt->Control.BitWidth != 8 || ecdt->Data.BitWidth != 8) { return; } /* Create the child device with the given unit number. */ child = BUS_ADD_CHILD(parent, parent, 0, "acpi_ec", ecdt->Uid); if (child == NULL) { kprintf("%s: can't add child\n", __func__); return; } /* Find and save the ACPI handle for this device. */ status = AcpiGetHandle(NULL, ecdt->Id, &h); if (ACPI_FAILURE(status)) { device_delete_child(parent, child); kprintf("%s: can't get handle\n", __func__); return; } acpi_set_handle(child, h); /* Set the data and CSR register addresses. */ bus_set_resource(child, SYS_RES_IOPORT, 0, ecdt->Data.Address, /*count*/1, -1); bus_set_resource(child, SYS_RES_IOPORT, 1, ecdt->Control.Address, /*count*/1, -1); /* * Store values for the probe/attach routines to use. Store the * ECDT GPE bit and set the global lock flag according to _GLK. * Note that it is not perfectly correct to be evaluating a method * before initializing devices, but in practice this function * should be safe to call at this point. */ params = kmalloc(sizeof(struct acpi_ec_params), M_TEMP, M_WAITOK | M_ZERO); params->gpe_handle = NULL; params->gpe_bit = ecdt->Gpe; params->uid = ecdt->Uid; acpi_GetInteger(h, "_GLK", ¶ms->glk); acpi_set_private(child, params); /* Finish the attach process. */ if (device_probe_and_attach(child) != 0) device_delete_child(parent, child); }
static int acpi_cpu_attach(device_t dev) { struct acpi_cpux_softc *sc = device_get_softc(dev); ACPI_HANDLE handle; device_t child; int cpu_id, cpu_features; struct acpi_softc *acpi_sc; handle = acpi_get_handle(dev); cpu_id = acpi_get_magic(dev); acpi_sc = acpi_device_get_parent_softc(dev); if (cpu_id == 0) { sysctl_ctx_init(&sc->glob_sysctl_ctx); sc->glob_sysctl_tree = SYSCTL_ADD_NODE(&sc->glob_sysctl_ctx, SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), OID_AUTO, "cpu", CTLFLAG_RD, 0, "node for CPU global settings"); if (sc->glob_sysctl_tree == NULL) return ENOMEM; } sysctl_ctx_init(&sc->pcpu_sysctl_ctx); sc->pcpu_sysctl_tree = SYSCTL_ADD_NODE(&sc->pcpu_sysctl_ctx, SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), OID_AUTO, device_get_nameunit(dev), CTLFLAG_RD, 0, "node for per-CPU settings"); if (sc->pcpu_sysctl_tree == NULL) { sysctl_ctx_free(&sc->glob_sysctl_ctx); return ENOMEM; } /* * Before calling any CPU methods, collect child driver feature hints * and notify ACPI of them. We support unified SMP power control * so advertise this ourselves. Note this is not the same as independent * SMP control where each CPU can have different settings. */ cpu_features = ACPI_PDC_MP_C1PXTX | ACPI_PDC_MP_C2C3; cpu_features |= acpi_cpu_md_features(); /* * CPU capabilities are specified as a buffer of 32-bit integers: * revision, count, and one or more capabilities. */ if (cpu_features) { ACPI_OBJECT_LIST arglist; uint32_t cap_set[3]; ACPI_OBJECT arg[4]; ACPI_STATUS status; /* UUID needed by _OSC evaluation */ static uint8_t cpu_oscuuid[16] = { 0x16, 0xA6, 0x77, 0x40, 0x0C, 0x29, 0xBE, 0x47, 0x9E, 0xBD, 0xD8, 0x70, 0x58, 0x71, 0x39, 0x53 }; arglist.Pointer = arg; arglist.Count = 4; arg[0].Type = ACPI_TYPE_BUFFER; arg[0].Buffer.Length = sizeof(cpu_oscuuid); arg[0].Buffer.Pointer = cpu_oscuuid; /* UUID */ arg[1].Type = ACPI_TYPE_INTEGER; arg[1].Integer.Value = 1; /* revision */ arg[2].Type = ACPI_TYPE_INTEGER; arg[2].Integer.Value = 2; /* # of capabilities integers */ arg[3].Type = ACPI_TYPE_BUFFER; arg[3].Buffer.Length = sizeof(cap_set[0]) * 2; /* capabilities buffer */ arg[3].Buffer.Pointer = (uint8_t *)cap_set; cap_set[0] = 0; cap_set[1] = cpu_features; status = AcpiEvaluateObject(handle, "_OSC", &arglist, NULL); if (!ACPI_SUCCESS(status)) { if (bootverbose) device_printf(dev, "_OSC failed, use _PDC\n"); arglist.Pointer = arg; arglist.Count = 1; arg[0].Type = ACPI_TYPE_BUFFER; arg[0].Buffer.Length = sizeof(cap_set); arg[0].Buffer.Pointer = (uint8_t *)cap_set; cap_set[0] = 1; /* revision */ cap_set[1] = 1; /* # of capabilities integers */ cap_set[2] = cpu_features; AcpiEvaluateObject(handle, "_PDC", &arglist, NULL); } } child = BUS_ADD_CHILD(dev, dev, 0, "cpu_cst", -1); if (child == NULL) return ENXIO; acpi_set_handle(child, handle); acpi_set_magic(child, cpu_id); sc->cpux_cst = child; child = BUS_ADD_CHILD(dev, dev, 0, "cpu_pst", -1); if (child == NULL) return ENXIO; acpi_set_handle(child, handle); acpi_set_magic(child, cpu_id); bus_generic_attach(dev); AcpiInstallNotifyHandler(handle, ACPI_DEVICE_NOTIFY, acpi_cpu_notify, sc); return 0; }
static int acpi_cpu_attach(device_t dev) { struct acpi_cpu_softc *sc = device_get_softc(dev); ACPI_HANDLE handle; device_t child; int cpu_id, cpu_features; struct acpi_softc *acpi_sc; sc->cpu_dev = dev; handle = acpi_get_handle(dev); cpu_id = acpi_get_magic(dev); acpi_sc = acpi_device_get_parent_softc(dev); if (cpu_id == 0) { sysctl_ctx_init(&sc->glob_sysctl_ctx); sc->glob_sysctl_tree = SYSCTL_ADD_NODE(&sc->glob_sysctl_ctx, SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), OID_AUTO, "cpu", CTLFLAG_RD, 0, "node for CPU global settings"); if (sc->glob_sysctl_tree == NULL) return ENOMEM; } sysctl_ctx_init(&sc->pcpu_sysctl_ctx); sc->pcpu_sysctl_tree = SYSCTL_ADD_NODE(&sc->pcpu_sysctl_ctx, SYSCTL_CHILDREN(acpi_sc->acpi_sysctl_tree), OID_AUTO, device_get_nameunit(dev), CTLFLAG_RD, 0, "node for per-CPU settings"); if (sc->pcpu_sysctl_tree == NULL) { sysctl_ctx_free(&sc->glob_sysctl_ctx); return ENOMEM; } /* * Before calling any CPU methods, collect child driver feature hints * and notify ACPI of them. We support unified SMP power control * so advertise this ourselves. Note this is not the same as independent * SMP control where each CPU can have different settings. */ cpu_features = ACPI_PDC_MP_C1PXTX | ACPI_PDC_MP_C2C3; cpu_features |= acpi_cpu_md_features(); /* * CPU capabilities are specified as a buffer of 32-bit integers: * revision, count, and one or more capabilities. */ if (cpu_features) { uint32_t cap_set[3]; ACPI_STATUS status; cap_set[0] = 0; cap_set[1] = cpu_features; status = acpi_eval_osc(dev, handle, "4077A616-290C-47BE-9EBD-D87058713953", 1, cap_set, 2); if (ACPI_FAILURE(status)) { ACPI_OBJECT_LIST arglist; ACPI_OBJECT arg[4]; if (bootverbose) device_printf(dev, "_OSC failed, using _PDC\n"); arglist.Pointer = arg; arglist.Count = 1; arg[0].Type = ACPI_TYPE_BUFFER; arg[0].Buffer.Length = sizeof(cap_set); arg[0].Buffer.Pointer = (uint8_t *)cap_set; cap_set[0] = 1; /* revision */ cap_set[1] = 1; /* # of capabilities integers */ cap_set[2] = cpu_features; AcpiEvaluateObject(handle, "_PDC", &arglist, NULL); } } ksnprintf(sc->cpu_sensdev.xname, sizeof(sc->cpu_sensdev.xname), "%s", device_get_nameunit(dev)); sensordev_install(&sc->cpu_sensdev); child = BUS_ADD_CHILD(dev, dev, 0, "cpu_cst", -1); if (child == NULL) return ENXIO; acpi_set_handle(child, handle); acpi_set_magic(child, cpu_id); sc->cpu_cst = child; child = BUS_ADD_CHILD(dev, dev, 0, "cpu_pst", -1); if (child == NULL) return ENXIO; acpi_set_handle(child, handle); acpi_set_magic(child, cpu_id); sc->cpu_pst = child; bus_generic_probe(dev); bus_generic_attach(dev); AcpiInstallNotifyHandler(handle, ACPI_DEVICE_NOTIFY, acpi_cpu_notify, sc); return 0; }