Exemplo n.º 1
0
static status_t
acpi_cpuidle_setup(acpi_cpuidle_driver_info *device)
{
	// _PDC is deprecated in the ACPI 3.0, we will try _OSC firstly
	// and fall back to _PDC if _OSC fail
	status_t status = acpi_eval_osc(device);
	if (status != B_OK)
		status = acpi_eval_pdc(device);
	if (status != B_OK) {
		dprintf("failed to eval _OSC and _PDC\n");
		return status;
	}

	acpi_data buffer;
	buffer.pointer = NULL;
	buffer.length = ACPI_ALLOCATE_BUFFER;

	dprintf("evaluate _CST @%p\n", device->acpi_cookie);
	status = device->acpi->evaluate_method(device->acpi_cookie, "_CST", NULL,
		&buffer);
	if (status != B_OK) {
		dprintf("failed to get _CST\n");
		return B_IO_ERROR;
	}

	acpi_object_type *object = (acpi_object_type *)buffer.pointer;
	if (object->object_type != ACPI_TYPE_PACKAGE)
		dprintf("invalid _CST type\n");
	if (object->data.package.count < 2)
		dprintf("invalid _CST count\n");

	acpi_object_type *pointer = object->data.package.objects;
	if (pointer[0].object_type != ACPI_TYPE_INTEGER)
		dprintf("invalid _CST type 2\n");
	uint32 n = pointer[0].data.integer;
	if (n != object->data.package.count - 1)
		dprintf("invalid _CST count 2\n");
	if (n > 8)
		dprintf("_CST has too many states\n");
	dprintf("cpuidle found %" B_PRId32 " cstates\n", n);
	uint32 count = 1;
	for (uint32 i = 1; i <= n; i++) {
		pointer = &object->data.package.objects[i];
		if (acpi_cstate_add(pointer, &sAcpiDevice.cStates[count]) == B_OK)
			++count;
	}
	sAcpiDevice.cStateCount = count;
	free(buffer.pointer);

	// TODO we assume BM is a must and ARB_DIS is always available
	device->flags |= ACPI_FLAG_C_ARB | ACPI_FLAG_C_BM;

	acpi_cstate_quirks(device);

	return B_OK;
}
Exemplo n.º 2
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;
}