qemu/hw/misc/test_component.c
<<
>>
Prefs
   1/*
   2 * Implementation of irq test component, used to emulate interrupt generation
   3 * capabilities for testing purposes.
   4 *
   5 * 2015 Aggios, Inc.
   6 *
   7 * Written by Strahinja Jankovic <strahinja.jankovic@aggios.com>
   8 *
   9 * Permission is hereby granted, free of charge, to any person obtaining a copy
  10 * of this software and associated documentation files (the "Software"), to deal
  11 * in the Software without restriction, including without limitation the rights
  12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  13 * copies of the Software, and to permit persons to whom the Software is
  14 * furnished to do so, subject to the following conditions:
  15 *
  16 * The above copyright notice and this permission notice shall be included in
  17 * all copies or substantial portions of the Software.
  18 *
  19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  25 * THE SOFTWARE.
  26 */
  27
  28#include "qemu/osdep.h"
  29#include "hw/sysbus.h"
  30#include "hw/register.h"
  31#include "qemu/log.h"
  32
  33#ifndef IRQ_TEST_COMPONENT_ERR_DEBUG
  34#define IRQ_TEST_COMPONENT_ERR_DEBUG 0
  35#endif
  36
  37#define TYPE_IRQ_TEST_COMPONENT "qemu.irq-test-component"
  38
  39#define IRQ_TEST_COMPONENT(obj) \
  40     OBJECT_CHECK(IRQTestComponent, (obj), TYPE_IRQ_TEST_COMPONENT)
  41
  42REG32(CONFIG, 0x0)
  43REG32(STATUS, 0x4)
  44    FIELD(STATUS, POWER, 1, 0)
  45    FIELD(STATUS, HALT, 1, 1)
  46REG32(DATA, 0x8)
  47REG32(IRQ_STATUS, 0x10)
  48    FIELD(IRQ_STATUS, IRQ0, 1, 0)
  49REG32(IRQ_MASK, 0x14)
  50    FIELD(IRQ_MASK, IRQ0, 1, 0)
  51REG32(IRQ_ENABLE, 0x18)
  52    FIELD(IRQ_ENABLE, IRQ0, 1, 0)
  53REG32(IRQ_DISABLE, 0x1c)
  54    FIELD(IRQ_DISABLE, IRQ0, 1, 0)
  55REG32(IRQ_TRIGGER, 0x20)
  56    FIELD(IRQ_TRIGGER, IRQ0, 1, 0)
  57
  58#define R_MAX ((R_IRQ_TRIGGER) + 1)
  59
  60typedef struct IRQTestComponent {
  61    SysBusDevice parent_obj;
  62    MemoryRegion iomem;
  63
  64    qemu_irq irq;
  65    qemu_irq pmu_wake;
  66
  67    uint32_t regs[R_MAX];
  68    RegisterInfo regs_info[R_MAX];
  69} IRQTestComponent;
  70
  71static void itc_update_irq(void *opaque)
  72{
  73    IRQTestComponent *s = IRQ_TEST_COMPONENT(opaque);
  74    bool pending = s->regs[R_IRQ_STATUS] & (~s->regs[R_IRQ_MASK]) &
  75                    R_IRQ_STATUS_IRQ0_MASK;
  76
  77    qemu_set_irq(s->irq, pending);
  78    qemu_set_irq(s->pmu_wake, pending);
  79}
  80
  81/* Used to trigger irq from qtest. */
  82static void itc_generate_irq(void *opaque, int n, int level)
  83{
  84    IRQTestComponent *s = IRQ_TEST_COMPONENT(opaque);
  85
  86    s->regs[R_IRQ_STATUS] &= ~R_IRQ_STATUS_IRQ0_MASK;
  87    s->regs[R_IRQ_STATUS] |= level;
  88
  89    itc_update_irq(s);
  90}
  91
  92/* Generate status read. */
  93
  94static uint64_t itc_status_postr(RegisterInfo *reg, uint64_t val64)
  95{
  96    IRQTestComponent *s = IRQ_TEST_COMPONENT(reg->opaque);
  97    DeviceState *dev = DEVICE(s);
  98    uint32_t tmp = val64;
  99
 100    /* Update pwrstat with current power and halt status */
 101    tmp = deposit32(tmp, R_STATUS_POWER_SHIFT, 1, dev->ps.power);
 102    tmp = deposit32(tmp, R_STATUS_HALT_SHIFT, 1, dev->ps.halt);
 103
 104    return tmp;
 105}
 106
 107static void itc_irq_status_postw(RegisterInfo *reg, uint64_t val64)
 108{
 109    IRQTestComponent *s = IRQ_TEST_COMPONENT(reg->opaque);
 110
 111    itc_update_irq(s);
 112}
 113
 114static void itc_irq_enable_postw(RegisterInfo *reg, uint64_t val64)
 115{
 116    IRQTestComponent *s = IRQ_TEST_COMPONENT(reg->opaque);
 117    uint32_t val = val64;
 118
 119    s->regs[R_IRQ_MASK] &= ~val;
 120    itc_update_irq(s);
 121}
 122
 123static void itc_irq_disable_postw(RegisterInfo *reg, uint64_t val64)
 124{
 125    IRQTestComponent *s = IRQ_TEST_COMPONENT(reg->opaque);
 126    uint32_t val = val64;
 127
 128    s->regs[R_IRQ_MASK] |= val;
 129    itc_update_irq(s);
 130}
 131
 132static void itc_irq_trigger_postw(RegisterInfo *reg, uint64_t val64)
 133{
 134    IRQTestComponent *s = IRQ_TEST_COMPONENT(reg->opaque);
 135    uint32_t val = val64;
 136
 137    s->regs[R_IRQ_STATUS] |= val;
 138    itc_update_irq(s);
 139}
 140
 141static RegisterAccessInfo irq_test_comp_regs_info[] = {
 142    {   .name = "CONFIG",  .decode.addr = A_CONFIG,
 143        .rsvd = 0xffffffff,
 144    },{   .name = "STATUS",  .decode.addr = A_STATUS,
 145        .rsvd = 0xfffffffe,
 146        .ro = 0xfffffffe,
 147        .post_read = itc_status_postr,
 148    },{   .name = "DATA",  .decode.addr = A_DATA,
 149    },{   .name = "IRQ_STATUS",  .decode.addr = A_IRQ_STATUS,
 150        .w1c = 0xffffffff,
 151        .rsvd = 0xfffffffe,
 152        .post_write = itc_irq_status_postw,
 153    },{   .name = "IRQ_MASK",  .decode.addr = A_IRQ_MASK,
 154        .ro = 0xffffffff,
 155        .rsvd = 0xfffffffe,
 156        .reset = 0xffffffff,
 157    },{   .name = "IRQ_ENABLE",  .decode.addr = A_IRQ_ENABLE,
 158        .rsvd = 0xfffffffe,
 159        .post_write = itc_irq_enable_postw,
 160    },{   .name = "IRQ_DISABLE",  .decode.addr = A_IRQ_DISABLE,
 161        .rsvd = 0xfffffffe,
 162        .post_write = itc_irq_disable_postw,
 163    },{   .name = "IRQ_TRIGGER",  .decode.addr = A_IRQ_TRIGGER,
 164        .rsvd = 0xfffffffe,
 165        .post_write = itc_irq_trigger_postw,
 166    }
 167};
 168
 169static void irq_test_comp_reset(DeviceState *dev)
 170{
 171    IRQTestComponent *s = IRQ_TEST_COMPONENT(dev);
 172    unsigned int i;
 173
 174    for (i = 0; i < ARRAY_SIZE(s->regs_info); ++i) {
 175        register_reset(&s->regs_info[i]);
 176    }
 177    itc_update_irq(s);
 178}
 179
 180static uint64_t irq_test_comp_read(void *opaque, hwaddr addr, unsigned size)
 181{
 182    IRQTestComponent *s = IRQ_TEST_COMPONENT(opaque);
 183    RegisterInfo *r = &s->regs_info[addr / 4];
 184
 185    if (!r->data) {
 186        qemu_log_mask(LOG_GUEST_ERROR,
 187                      "%s: Decode error: read from %" HWADDR_PRIx "\n",
 188                      object_get_canonical_path(OBJECT(s)),
 189                      addr);
 190        return 0;
 191    }
 192    return register_read(r);
 193}
 194
 195static void irq_test_comp_write(void *opaque, hwaddr addr, uint64_t value,
 196                      unsigned size)
 197{
 198    IRQTestComponent *s = IRQ_TEST_COMPONENT(opaque);
 199    RegisterInfo *r = &s->regs_info[addr / 4];
 200
 201    if (!r->data) {
 202        qemu_log_mask(LOG_GUEST_ERROR,
 203                      "%s: Decode error: write %" HWADDR_PRIx "=%" PRIx64 "\n",
 204                      object_get_canonical_path(OBJECT(s)),
 205                      addr, value);
 206        return;
 207    }
 208    register_write(r, value, ~0);
 209}
 210
 211static const MemoryRegionOps irq_test_comp_ops = {
 212    .read = irq_test_comp_read,
 213    .write = irq_test_comp_write,
 214    .endianness = DEVICE_LITTLE_ENDIAN,
 215    .valid = {
 216        .min_access_size = 4,
 217        .max_access_size = 4,
 218    },
 219};
 220
 221static void irq_test_comp_realize(DeviceState *dev, Error **errp)
 222{
 223    IRQTestComponent *s = IRQ_TEST_COMPONENT(dev);
 224    const char *prefix = object_get_canonical_path(OBJECT(dev));
 225    unsigned int i;
 226
 227    for (i = 0; i < ARRAY_SIZE(irq_test_comp_regs_info); ++i) {
 228        RegisterInfo *r = &s->regs_info[
 229                            irq_test_comp_regs_info[i].decode.addr/4];
 230
 231        *r = (RegisterInfo) {
 232            .data = (uint8_t *)&s->regs[
 233                    irq_test_comp_regs_info[i].decode.addr/4],
 234            .data_size = sizeof(uint32_t),
 235            .access = &irq_test_comp_regs_info[i],
 236            .debug = IRQ_TEST_COMPONENT_ERR_DEBUG,
 237            .prefix = prefix,
 238            .opaque = s,
 239        };
 240        register_init(r);
 241    }
 242}
 243
 244static void irq_test_comp_init(Object *obj)
 245{
 246    IRQTestComponent *s = IRQ_TEST_COMPONENT(obj);
 247    DeviceState *dev = DEVICE(obj);
 248    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
 249
 250    memory_region_init_io(&s->iomem, obj, &irq_test_comp_ops, s,
 251                          TYPE_IRQ_TEST_COMPONENT, R_MAX * 4);
 252    sysbus_init_mmio(sbd, &s->iomem);
 253    sysbus_init_irq(sbd, &s->irq);
 254
 255    /* Pin used from qtest to trigger interrupt. */
 256    qdev_init_gpio_in(dev, itc_generate_irq, 1);
 257    /* Pin used to signal wakeup request to PMU */
 258    qdev_init_gpio_out_named(dev, &s->pmu_wake, "wake", 1);
 259}
 260
 261static const VMStateDescription vmstate_irq_test_comp = {
 262    .name = TYPE_IRQ_TEST_COMPONENT,
 263    .version_id = 1,
 264    .minimum_version_id = 1,
 265    .minimum_version_id_old = 1,
 266    .fields = (VMStateField[]) {
 267        VMSTATE_UINT32_ARRAY(regs, IRQTestComponent, R_MAX),
 268        VMSTATE_END_OF_LIST(),
 269    }
 270};
 271
 272static void irq_test_comp_class_init(ObjectClass *klass, void *data)
 273{
 274    DeviceClass *dc = DEVICE_CLASS(klass);
 275
 276    dc->reset = irq_test_comp_reset;
 277    dc->realize = irq_test_comp_realize;
 278    dc->vmsd = &vmstate_irq_test_comp;
 279}
 280
 281static const TypeInfo irq_test_comp_info = {
 282    .name          = TYPE_IRQ_TEST_COMPONENT,
 283    .parent        = TYPE_SYS_BUS_DEVICE,
 284    .instance_size = sizeof(IRQTestComponent),
 285    .instance_init = irq_test_comp_init,
 286    .class_init    = irq_test_comp_class_init,
 287};
 288
 289static void irq_test_comp_register_types(void)
 290{
 291    type_register_static(&irq_test_comp_info);
 292}
 293
 294type_init(irq_test_comp_register_types)
 295