Ticket #8451: 0001-acpi_cpuidle-try-to-decode-cstate-from-acpi-_CST.2.patch

File 0001-acpi_cpuidle-try-to-decode-cstate-from-acpi-_CST.2.patch, 8.6 KB (added by yongcong, 12 years ago)
  • new file src/add-ons/kernel/drivers/power/acpi_cpuidle/Jamfile

    From 7f859cd6328be64e4078c7a124a55d36943e7437 Mon Sep 17 00:00:00 2001
    From: Yongcong Du <ycdu.vmcore@gmail.com>
    Date: Fri, 6 Apr 2012 00:12:58 +0800
    Subject: [PATCH] acpi_cpuidle: try to decode cstate from acpi _CST
    
    ---
     .../kernel/drivers/power/acpi_cpuidle/Jamfile      |    7 +
     .../drivers/power/acpi_cpuidle/acpi_cpuidle.cpp    |  341 ++++++++++++++++++++
     2 files changed, 348 insertions(+)
     create mode 100644 src/add-ons/kernel/drivers/power/acpi_cpuidle/Jamfile
     create mode 100644 src/add-ons/kernel/drivers/power/acpi_cpuidle/acpi_cpuidle.cpp
    
    diff --git a/src/add-ons/kernel/drivers/power/acpi_cpuidle/Jamfile b/src/add-ons/kernel/drivers/power/acpi_cpuidle/Jamfile
    new file mode 100644
    index 0000000..cc278b9
    - +  
     1SubDir HAIKU_TOP src add-ons kernel drivers power acpi_cpuidle ;
     2
     3KernelAddon acpi_cpuidle :
     4    acpi_cpuidle.cpp
     5    ;
     6
     7Depends acpi_cpuidle : acpi ;
  • new file src/add-ons/kernel/drivers/power/acpi_cpuidle/acpi_cpuidle.cpp

    diff --git a/src/add-ons/kernel/drivers/power/acpi_cpuidle/acpi_cpuidle.cpp b/src/add-ons/kernel/drivers/power/acpi_cpuidle/acpi_cpuidle.cpp
    new file mode 100644
    index 0000000..e842d21
    - +  
     1/*
     2 * Copyright 2012, Haiku, Inc. All Rights Reserved.
     3 *
     4 * Distributed under the terms of the MIT License.
     5 *
     6 * Authors:
     7 *      Yongcong Du <ycdu.vmcore@gmail.com>
     8 */
     9
     10#include <KernelExport.h>
     11#include <Drivers.h>
     12#include <Errors.h>
     13#include <string.h>
     14
     15#include <stdio.h>
     16#include <stdlib.h>
     17
     18#include <ACPI.h>
     19
     20#define ACPI_CPUIDLE_MODULE_NAME "drivers/power/acpi_cpuidle/driver_v1"
     21
     22#define ACPI_CPUIDLE_DEVICE_MODULE_NAME "drivers/power/acpi_cpuidle/device_v1"
     23
     24/* Base Namespace devices are published to */
     25#define ACPI_CPUIDLE_BASENAME "power/acpi_cpuidle/%d"
     26
     27// name of pnp generator of path ids
     28#define ACPI_CPUIDLE_PATHID_GENERATOR "acpi_cpuidle/path_id"
     29
     30static device_manager_info *sDeviceManager;
     31
     32struct acpicpu_reg {
     33    uint8   reg_desc;
     34    uint16  reg_reslen;
     35    uint8   reg_spaceid;
     36    uint8   reg_bitwidth;
     37    uint8   reg_bitoffset;
     38    uint8   reg_accesssize;
     39    uint64  reg_addr;
     40} __packed;
     41
     42
     43typedef struct acpi_ns_device_info {
     44    device_node *node;
     45    acpi_device_module_info *acpi;
     46    acpi_device acpi_cookie;
     47} acpi_cpuidle_device_info;
     48
     49
     50static status_t
     51acpi_cpuidle_open(void *_cookie, const char *path, int flags, void **cookie)
     52{
     53    acpi_cpuidle_device_info *device = (acpi_cpuidle_device_info *)_cookie;
     54    *cookie = device;
     55    return B_OK;
     56}
     57
     58
     59static void
     60acpicpu_cstate_cst_add(acpi_object_type *object)
     61{
     62    if (object->object_type != ACPI_TYPE_PACKAGE) {
     63        dprintf("invalid _CST object\n");
     64        return;
     65    }
     66
     67    if (object->data.package.count != 4) {
     68        dprintf("invalid _CST number\n");
     69        return;
     70    }
     71
     72    // type
     73    acpi_object_type * pointer = &object->data.package.objects[1];
     74    if (pointer->object_type != ACPI_TYPE_INTEGER) {
     75        dprintf("invalid _CST elem type\n");
     76        return;
     77    }
     78    uint32 n = pointer->data.integer;
     79    if (n < 0 || n > 3) {
     80        dprintf("invalid _CST elem value\n");
     81        return;
     82    }
     83    dprintf("c%" B_PRId32 "\n", n);
     84
     85    // Latency
     86    pointer = &object->data.package.objects[2];
     87    if (pointer->object_type != ACPI_TYPE_INTEGER) {
     88        dprintf("invalid _CST elem type\n");
     89        return;
     90    }
     91    n = pointer->data.integer;
     92    dprintf("Latency: %" B_PRId32 "\n", n);
     93
     94    // power
     95    pointer = &object->data.package.objects[3];
     96    if (pointer->object_type != ACPI_TYPE_INTEGER) {
     97        dprintf("invalid _CST elem type\n");
     98        return;
     99    }
     100    n = pointer->data.integer;
     101    dprintf("power: %" B_PRId32 "\n", n);
     102
     103    // register
     104    pointer = &object->data.package.objects[0];
     105    if (pointer->object_type != ACPI_TYPE_BUFFER) {
     106        dprintf("invalid _CST elem type\n");
     107        return;
     108    }
     109    if (pointer->data.buffer.length < 15) {
     110        dprintf("invalid _CST elem length\n");
     111        return;
     112    }
     113    struct acpicpu_reg *reg = (struct acpicpu_reg *)pointer->data.buffer.buffer;
     114    switch (reg->reg_spaceid) {
     115        case ACPI_ADR_SPACE_SYSTEM_IO:
     116            dprintf("IO method\n");
     117            break;
     118        case ACPI_ADR_SPACE_FIXED_HARDWARE:
     119            dprintf("FFH method\n");
     120            break;
     121    }
     122
     123}
     124
     125
     126static status_t
     127acpi_cpuidle_read(void *_cookie, off_t position, void *buf, size_t *num_bytes)
     128{
     129    acpi_cpuidle_device_info *device = (acpi_cpuidle_device_info *)_cookie;
     130    status_t status = B_ERROR;
     131
     132    acpi_data buffer;
     133    buffer.pointer = NULL;
     134    buffer.length = ACPI_ALLOCATE_BUFFER;
     135
     136    if (*num_bytes < 1)
     137        return B_IO_ERROR;
     138    status = device->acpi->evaluate_method(device->acpi_cookie, "_CST", NULL,
     139        &buffer);
     140    if (status != B_OK) {
     141        dprintf("failed to get _CST\n");
     142        return B_IO_ERROR;
     143    }
     144
     145    acpi_object_type *object = (acpi_object_type *)buffer.pointer;
     146    if (object->object_type != ACPI_TYPE_PACKAGE)
     147        dprintf("invalid _CST type\n");
     148    if (object->data.package.count < 2)
     149        dprintf("invalid _CST count\n");
     150
     151    acpi_object_type *pointer = object->data.package.objects;
     152    if (pointer[0].object_type != ACPI_TYPE_INTEGER)
     153        dprintf("invalid _CST type 2\n");
     154    uint32 n = pointer[0].data.integer;
     155    if (n != object->data.package.count-1)
     156        dprintf("invalid _CST count 2\n");
     157    if (n > 8)
     158        dprintf("_CST has too many states\n");
     159    for (uint32 i = 0; i < n; i++) {
     160        pointer = &object->data.package.objects[i];
     161        acpicpu_cstate_cst_add(pointer);
     162    }
     163
     164    return B_OK;
     165}
     166
     167
     168static status_t
     169acpi_cpuidle_write(void *cookie, off_t position, const void *buffer, size_t *num_bytes)
     170{
     171    return B_ERROR;
     172}
     173
     174
     175static status_t
     176acpi_cpuidle_close (void *cookie)
     177{
     178    return B_OK;
     179}
     180
     181
     182static status_t
     183acpi_cpuidle_free (void *cookie)
     184{
     185    return B_OK;
     186}
     187
     188
     189//  #pragma mark - driver module API
     190
     191
     192static float
     193acpi_cpuidle_support(device_node *parent)
     194{
     195    const char *bus;
     196    uint32 device_type;
     197
     198    // make sure parent is really the ACPI bus manager
     199    if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
     200        return -1;
     201
     202    if (strcmp(bus, "acpi"))
     203        return 0.0;
     204
     205    // check whether it's really a cpuidle Device
     206    if (sDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM, &device_type, false) != B_OK
     207        || device_type != ACPI_TYPE_PROCESSOR) {
     208        return 0.0;
     209    }
     210
     211    return 0.6;
     212}
     213
     214
     215static status_t
     216acpi_cpuidle_register_device(device_node *node)
     217{
     218    device_attr attrs[] = {
     219        { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { string: "ACPI CPU IDLE" }},
     220        { NULL }
     221    };
     222
     223    return sDeviceManager->register_node(node, ACPI_CPUIDLE_MODULE_NAME, attrs, NULL, NULL);
     224}
     225
     226
     227static status_t
     228acpi_cpuidle_init_driver(device_node *node, void **_driverCookie)
     229{
     230    *_driverCookie = node;
     231    return B_OK;
     232}
     233
     234
     235static void
     236acpi_cpuidle_uninit_driver(void *driverCookie)
     237{
     238}
     239
     240
     241static status_t
     242acpi_cpuidle_register_child_devices(void *_cookie)
     243{
     244    device_node *node = (device_node *)_cookie;
     245    int path_id;
     246    char name[128];
     247
     248    path_id = sDeviceManager->create_id(ACPI_CPUIDLE_PATHID_GENERATOR);
     249    if (path_id < 0) {
     250        dprintf("acpi_cpuidle_register_child_devices: couldn't create a path_id\n");
     251        return B_ERROR;
     252    }
     253    snprintf(name, sizeof(name), ACPI_CPUIDLE_BASENAME, path_id);
     254
     255    return sDeviceManager->publish_device(node, name, ACPI_CPUIDLE_DEVICE_MODULE_NAME);
     256}
     257
     258
     259static status_t
     260acpi_cpuidle_init_device(void *_cookie, void **cookie)
     261{
     262    device_node *node = (device_node *)_cookie;
     263    acpi_cpuidle_device_info *device;
     264    device_node *parent;
     265
     266    device = (acpi_cpuidle_device_info *)calloc(1, sizeof(*device));
     267    if (device == NULL)
     268        return B_NO_MEMORY;
     269
     270    device->node = node;
     271
     272    parent = sDeviceManager->get_parent_node(node);
     273    sDeviceManager->get_driver(parent, (driver_module_info **)&device->acpi,
     274        (void **)&device->acpi_cookie);
     275    sDeviceManager->put_node(parent);
     276
     277    *cookie = device;
     278    return B_OK;
     279}
     280
     281
     282static void
     283acpi_cpuidle_uninit_device(void *_cookie)
     284{
     285    acpi_cpuidle_device_info *device = (acpi_cpuidle_device_info *)_cookie;
     286    free(device);
     287}
     288
     289
     290module_dependency module_dependencies[] = {
     291    { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager },
     292    {}
     293};
     294
     295
     296driver_module_info acpi_cpuidle_driver_module = {
     297    {
     298        ACPI_CPUIDLE_MODULE_NAME,
     299        0,
     300        NULL
     301    },
     302
     303    acpi_cpuidle_support,
     304    acpi_cpuidle_register_device,
     305    acpi_cpuidle_init_driver,
     306    acpi_cpuidle_uninit_driver,
     307    acpi_cpuidle_register_child_devices,
     308    NULL,   // rescan
     309    NULL,   // removed
     310};
     311
     312
     313struct device_module_info acpi_cpuidle_device_module = {
     314    {
     315        ACPI_CPUIDLE_DEVICE_MODULE_NAME,
     316        0,
     317        NULL
     318    },
     319
     320    acpi_cpuidle_init_device,
     321    acpi_cpuidle_uninit_device,
     322    NULL,
     323
     324    acpi_cpuidle_open,
     325    acpi_cpuidle_close,
     326    acpi_cpuidle_free,
     327    acpi_cpuidle_read,
     328    acpi_cpuidle_write,
     329    NULL,
     330    NULL,
     331
     332    NULL,
     333    NULL
     334};
     335
     336
     337module_info *modules[] = {
     338    (module_info *)&acpi_cpuidle_driver_module,
     339    (module_info *)&acpi_cpuidle_device_module,
     340    NULL
     341};