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

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

    From 3f093600e36ed2a94be287d1b006d1cacd1d28f2 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      |   15 +
     .../drivers/power/acpi_cpuidle/acpi_cpuidle.c      |  338 ++++++++++++++++++++
     2 files changed, 353 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.c
    
    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..be8f60b
    - +  
     1SubDir HAIKU_TOP src add-ons kernel drivers power acpi_cpuidle ;
     2
     3SetSubDirSupportedPlatformsBeOSCompatible ;
     4
     5if $(TARGET_PLATFORM) != haiku {
     6    # Needed for <ACPI.h>. Unfortunately we also get the other headers there,
     7    # that we don't really want.
     8    UsePublicHeaders drivers ;
     9}
     10
     11KernelAddon acpi_cpuidle :
     12    acpi_cpuidle.c
     13    ;
     14
     15Depends acpi_cpuidle : acpi ;
  • new file src/add-ons/kernel/drivers/power/acpi_cpuidle/acpi_cpuidle.c

    diff --git a/src/add-ons/kernel/drivers/power/acpi_cpuidle/acpi_cpuidle.c b/src/add-ons/kernel/drivers/power/acpi_cpuidle/acpi_cpuidle.c
    new file mode 100644
    index 0000000..03fca0d
    - +  
     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    acpi_object_type* pointer;
     63    if (object->object_type != ACPI_TYPE_PACKAGE) {
     64        dprintf("invalid _CST object\n");
     65        return;
     66    }
     67    if (object->data.package.count != 4) {
     68        dprintf("invalid _CST number\n");
     69        return;
     70    }
     71    //type
     72    pointer = &object->data.package.objects[1];
     73    if (pointer->object_type != ACPI_TYPE_INTEGER) {
     74        dprintf("invalid _CST elem type\n");
     75        return;
     76    }
     77    uint32 n = pointer->data.integer;
     78    if (n < 0 || n > 3) {
     79        dprintf("invalid _CST elem value\n");
     80        return;
     81    }
     82    dprintf("c%u\n", n);
     83    //Latency
     84    pointer = &object->data.package.objects[2];
     85    if (pointer->object_type != ACPI_TYPE_INTEGER) {
     86        dprintf("invalid _CST elem type\n");
     87        return;
     88    }
     89    n = pointer->data.integer;
     90    dprintf("Latency: %u\n", n);
     91    //power
     92    pointer = &object->data.package.objects[3];
     93    if (pointer->object_type != ACPI_TYPE_INTEGER) {
     94        dprintf("invalid _CST elem type\n");
     95        return;
     96    }
     97    n = pointer->data.integer;
     98    dprintf("power: %u\n", n);
     99    //register
     100    pointer = &object->data.package.objects[0];
     101    if (pointer->object_type != ACPI_TYPE_BUFFER) {
     102        dprintf("invalid _CST elem type\n");
     103        return;
     104    }
     105    if (pointer->data.buffer.length < 15) {
     106        dprintf("invalid _CST elem length\n");
     107        return;
     108    }
     109    struct acpicpu_reg *reg = (struct acpicpu_reg *)pointer->data.buffer.buffer;
     110    switch (reg->reg_spaceid) {
     111        case ACPI_ADR_SPACE_SYSTEM_IO:
     112            dprintf("IO method\n");
     113            break;
     114        case ACPI_ADR_SPACE_FIXED_HARDWARE:
     115            dprintf("FFH method\n");
     116            break;
     117    }
     118
     119}
     120
     121
     122static status_t
     123acpi_cpuidle_read(void *_cookie, off_t position, void *buf, size_t *num_bytes)
     124{
     125    acpi_cpuidle_device_info* device = (acpi_cpuidle_device_info*)_cookie;
     126
     127    acpi_data buffer;
     128    buffer.pointer = NULL;
     129    buffer.length = ACPI_ALLOCATE_BUFFER;
     130    acpi_object_type* object;
     131    acpi_object_type* pointer;
     132    status_t status = B_ERROR;
     133    uint32 i;
     134
     135    if (*num_bytes < 1)
     136        return B_IO_ERROR;
     137    status = device->acpi->evaluate_method(device->acpi_cookie, "_CST", NULL,
     138        &buffer);
     139    if (status != B_OK) {
     140        dprintf("failed to get _CST\n");
     141        return B_IO_ERROR;
     142    }
     143
     144    object = (acpi_object_type*)buffer.pointer;
     145    if (object->object_type != ACPI_TYPE_PACKAGE)
     146        dprintf("invalid _CST type\n");
     147    if (object->data.package.count < 2)
     148        dprintf("invalid _CST count\n");
     149
     150    pointer = object->data.package.objects;
     151    if (pointer[0].object_type != ACPI_TYPE_INTEGER)
     152        dprintf("invalid _CST type 2\n");
     153    uint32 n = pointer[0].data.integer;
     154    if (n != object->data.package.count-1)
     155        dprintf("invalid _CST count 2\n");
     156    if (n > 8)
     157        dprintf("_CST has too many states\n");
     158    for (i = 0; i < n; i++) {
     159        pointer = &object->data.package.objects[i];
     160        acpicpu_cstate_cst_add(pointer);
     161    }
     162
     163    return B_OK;
     164}
     165
     166
     167static status_t
     168acpi_cpuidle_write(void *cookie, off_t position, const void *buffer, size_t *num_bytes)
     169{
     170    return B_ERROR;
     171}
     172
     173
     174static status_t
     175acpi_cpuidle_close (void *cookie)
     176{
     177    return B_OK;
     178}
     179
     180
     181static status_t
     182acpi_cpuidle_free (void *cookie)
     183{
     184    return B_OK;
     185}
     186
     187
     188//  #pragma mark - driver module API
     189
     190
     191static float
     192acpi_cpuidle_support(device_node *parent)
     193{
     194    const char *bus;
     195    uint32 device_type;
     196
     197    // make sure parent is really the ACPI bus manager
     198    if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false))
     199        return -1;
     200
     201    if (strcmp(bus, "acpi"))
     202        return 0.0;
     203
     204    // check whether it's really a cpuidle Device
     205    if (sDeviceManager->get_attr_uint32(parent, ACPI_DEVICE_TYPE_ITEM, &device_type, false) != B_OK
     206        || device_type != ACPI_TYPE_PROCESSOR) {
     207        return 0.0;
     208    }
     209
     210    return 0.6;
     211}
     212
     213
     214static status_t
     215acpi_cpuidle_register_device(device_node *node)
     216{
     217    device_attr attrs[] = {
     218        { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, { string: "ACPI CPU IDLE" }},
     219        { NULL }
     220    };
     221
     222    return sDeviceManager->register_node(node, ACPI_CPUIDLE_MODULE_NAME, attrs, NULL, NULL);
     223}
     224
     225
     226static status_t
     227acpi_cpuidle_init_driver(device_node *node, void **_driverCookie)
     228{
     229    *_driverCookie = node;
     230    return B_OK;
     231}
     232
     233
     234static void
     235acpi_cpuidle_uninit_driver(void *driverCookie)
     236{
     237}
     238
     239
     240static status_t
     241acpi_cpuidle_register_child_devices(void *_cookie)
     242{
     243    device_node *node = _cookie;
     244    int path_id;
     245    char name[128];
     246
     247    path_id = sDeviceManager->create_id(ACPI_CPUIDLE_PATHID_GENERATOR);
     248    if (path_id < 0) {
     249        dprintf("acpi_cpuidle_register_child_devices: couldn't create a path_id\n");
     250        return B_ERROR;
     251    }
     252    snprintf(name, sizeof(name), ACPI_CPUIDLE_BASENAME, path_id);
     253
     254    return sDeviceManager->publish_device(node, name, ACPI_CPUIDLE_DEVICE_MODULE_NAME);
     255}
     256
     257static status_t
     258acpi_cpuidle_init_device(void *_cookie, void **cookie)
     259{
     260    device_node *node = (device_node *)_cookie;
     261    acpi_cpuidle_device_info *device;
     262    device_node *parent;
     263
     264    device = (acpi_cpuidle_device_info *)calloc(1, sizeof(*device));
     265    if (device == NULL)
     266        return B_NO_MEMORY;
     267
     268    device->node = node;
     269
     270    parent = sDeviceManager->get_parent_node(node);
     271    sDeviceManager->get_driver(parent, (driver_module_info **)&device->acpi,
     272        (void **)&device->acpi_cookie);
     273    sDeviceManager->put_node(parent);
     274
     275    *cookie = device;
     276    return B_OK;
     277}
     278
     279
     280static void
     281acpi_cpuidle_uninit_device(void *_cookie)
     282{
     283    acpi_cpuidle_device_info *device = (acpi_cpuidle_device_info *)_cookie;
     284    free(device);
     285}
     286
     287
     288module_dependency module_dependencies[] = {
     289    { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&sDeviceManager },
     290    {}
     291};
     292
     293
     294driver_module_info acpi_cpuidle_driver_module = {
     295    {
     296        ACPI_CPUIDLE_MODULE_NAME,
     297        0,
     298        NULL
     299    },
     300
     301    acpi_cpuidle_support,
     302    acpi_cpuidle_register_device,
     303    acpi_cpuidle_init_driver,
     304    acpi_cpuidle_uninit_driver,
     305    acpi_cpuidle_register_child_devices,
     306    NULL,   // rescan
     307    NULL,   // removed
     308};
     309
     310
     311struct device_module_info acpi_cpuidle_device_module = {
     312    {
     313        ACPI_CPUIDLE_DEVICE_MODULE_NAME,
     314        0,
     315        NULL
     316    },
     317
     318    acpi_cpuidle_init_device,
     319    acpi_cpuidle_uninit_device,
     320    NULL,
     321
     322    acpi_cpuidle_open,
     323    acpi_cpuidle_close,
     324    acpi_cpuidle_free,
     325    acpi_cpuidle_read,
     326    acpi_cpuidle_write,
     327    NULL,
     328    NULL,
     329
     330    NULL,
     331    NULL
     332};
     333
     334module_info *modules[] = {
     335    (module_info *)&acpi_cpuidle_driver_module,
     336    (module_info *)&acpi_cpuidle_device_module,
     337    NULL
     338};