qemu/hw/misc/mem_ctrl.c
<<
>>
Prefs
   1/*
   2 * This file contains implementation of Memory Controller component.
   3 * Memory controller is used for managing state of RAM memory regions.
   4 * Based on pwr_/ret_cntrl inputs it can power up/down or put into
   5 * retention a RAM memory region.
   6 *
   7 * 2014 Aggios, Inc.
   8 *
   9 * Written by Strahinja Jankovic <strahinja.jankovic@aggios.com>
  10 *
  11 * Permission is hereby granted, free of charge, to any person obtaining a copy
  12 * of this software and associated documentation files (the "Software"), to deal
  13 * in the Software without restriction, including without limitation the rights
  14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15 * copies of the Software, and to permit persons to whom the Software is
  16 * furnished to do so, subject to the following conditions:
  17 *
  18 * The above copyright notice and this permission notice shall be included in
  19 * all copies or substantial portions of the Software.
  20 *
  21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  27 * THE SOFTWARE.
  28 */
  29
  30#include "qemu/osdep.h"
  31#include "hw/register.h"
  32#include "hw/qdev-properties.h"
  33#include "qemu/bitops.h"
  34#include "hw/sysbus.h"
  35#include "qapi/error.h"
  36#include "qemu/log.h"
  37
  38#define TYPE_MEM_CTRL "qemu.memory-controller"
  39
  40#define MEM_CTRL(obj) \
  41     OBJECT_CHECK(MemCtrl, (obj), TYPE_MEM_CTRL)
  42#define MEM_CTRL_PARENT_CLASS \
  43     object_class_get_parent(object_class_by_name(TYPE_MEM_CTRL))
  44
  45typedef struct MemCtrl {
  46    DeviceState parent_obj;
  47    MemoryRegion *mr_link;
  48    MemoryRegion pwrddown;
  49} MemCtrl;
  50
  51/* Read and write functions when memory region is disabled
  52 * (either powered down or put into retention).
  53 */
  54
  55static uint64_t mem_ctrl_pd_read(void *opaque, hwaddr addr, unsigned size)
  56{
  57    MemCtrl *s = MEM_CTRL(opaque);
  58
  59    qemu_log_mask(LOG_GUEST_ERROR,
  60                  "%s: Error: Memory unavailable (powered down/retained)!\n"
  61                  "\tAttempted read from %" HWADDR_PRIx "\n",
  62                  object_get_canonical_path(OBJECT(s)),
  63                  addr);
  64
  65    return 0;
  66}
  67
  68static void mem_ctrl_pd_write(void *opaque, hwaddr addr, uint64_t value,
  69                      unsigned size)
  70{
  71    MemCtrl *s = MEM_CTRL(opaque);
  72
  73    qemu_log_mask(LOG_GUEST_ERROR,
  74                  "%s: Error: Memory unavailable (powered down/retained)!\n"
  75                  "\tAttempted write to %" HWADDR_PRIx "=%" PRIx64 "\n",
  76                  object_get_canonical_path(OBJECT(s)),
  77                  addr, value);
  78}
  79
  80static const MemoryRegionOps mem_ctrl_pd_ops = {
  81    .read = mem_ctrl_pd_read,
  82    .write = mem_ctrl_pd_write,
  83    .endianness = DEVICE_LITTLE_ENDIAN,
  84    .valid = {
  85        .min_access_size = 4,
  86        .max_access_size = 4,
  87    },
  88};
  89
  90/* Power/retention control callbacks. */
  91
  92static void mem_ctrl_pwr_hlt_cntrl(void *opaque)
  93{
  94    DeviceState *dev = DEVICE(opaque);
  95    MemCtrl *s = MEM_CTRL(opaque);
  96
  97    memory_region_set_enabled(&s->pwrddown, !dev->ps.active);
  98}
  99
 100static void mem_ctrl_pwr_cntrl(void *opaque, int n, int level)
 101{
 102    DeviceClass *dc_parent = DEVICE_CLASS(MEM_CTRL_PARENT_CLASS);
 103
 104    dc_parent->pwr_cntrl(opaque, n, level);
 105    mem_ctrl_pwr_hlt_cntrl(opaque);
 106
 107    /* FIXME: Need to trash contents of memory */
 108}
 109
 110static void mem_ctrl_hlt_cntrl(void *opaque, int n, int level)
 111{
 112    DeviceClass *dc_parent = DEVICE_CLASS(MEM_CTRL_PARENT_CLASS);
 113
 114    dc_parent->hlt_cntrl(opaque, n, level);
 115    mem_ctrl_pwr_hlt_cntrl(opaque);
 116}
 117
 118static void mem_ctrl_realize(DeviceState *dev, Error **errp)
 119{
 120    MemCtrl *s = MEM_CTRL(dev);
 121    uint64_t mem_size;
 122
 123    if (!s->mr_link) {
 124        error_setg(errp, "mr_link not set!\n");
 125        return;
 126    }
 127
 128    mem_size = memory_region_size(s->mr_link);
 129    memory_region_init_io(&s->pwrddown, OBJECT(dev), &mem_ctrl_pd_ops, s,
 130                          TYPE_MEM_CTRL, mem_size);
 131    /* Create pwrddown as subregion */
 132    memory_region_add_subregion(s->mr_link, 0, &s->pwrddown);
 133}
 134
 135static void mem_ctrl_init(Object *obj)
 136{
 137    MemCtrl *s = MEM_CTRL(obj);
 138
 139    /* Link to RAM memory region. */
 140    object_property_add_link(obj, "mr", TYPE_MEMORY_REGION,
 141                             (Object **)&s->mr_link,
 142                             qdev_prop_allow_set_link_before_realize,
 143                             OBJ_PROP_LINK_UNREF_ON_RELEASE,
 144                             &error_abort);
 145}
 146
 147static void mem_ctrl_class_init(ObjectClass *klass, void *data)
 148{
 149    DeviceClass *dc = DEVICE_CLASS(klass);
 150
 151    dc->realize = mem_ctrl_realize;
 152    dc->pwr_cntrl = mem_ctrl_pwr_cntrl;
 153    dc->hlt_cntrl = mem_ctrl_hlt_cntrl;
 154}
 155
 156static const TypeInfo mem_ctrl_info = {
 157    .name          = TYPE_MEM_CTRL,
 158    .parent        = TYPE_DEVICE,
 159    .instance_size = sizeof(MemCtrl),
 160    .class_init    = mem_ctrl_class_init,
 161    .instance_init = mem_ctrl_init,
 162};
 163
 164static void mem_ctrl_register_types(void)
 165{
 166    type_register_static(&mem_ctrl_info);
 167}
 168
 169type_init(mem_ctrl_register_types)
 170