1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30#include "qemu/osdep.h"
31#include "hw/register-dep.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
52
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
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
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
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
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