pcie_aer: support configurable AER capa version
[qemu.git] / hw / core / register.c
1 /*
2 * Register Definition API
3 *
4 * Copyright (c) 2016 Xilinx Inc.
5 * Copyright (c) 2013 Peter Crosthwaite <peter.crosthwaite@xilinx.com>
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 */
17
18 #include "qemu/osdep.h"
19 #include "hw/register.h"
20 #include "hw/qdev.h"
21 #include "qemu/log.h"
22
23 static inline void register_write_val(RegisterInfo *reg, uint64_t val)
24 {
25 g_assert(reg->data);
26
27 switch (reg->data_size) {
28 case 1:
29 *(uint8_t *)reg->data = val;
30 break;
31 case 2:
32 *(uint16_t *)reg->data = val;
33 break;
34 case 4:
35 *(uint32_t *)reg->data = val;
36 break;
37 case 8:
38 *(uint64_t *)reg->data = val;
39 break;
40 default:
41 g_assert_not_reached();
42 }
43 }
44
45 static inline uint64_t register_read_val(RegisterInfo *reg)
46 {
47 switch (reg->data_size) {
48 case 1:
49 return *(uint8_t *)reg->data;
50 case 2:
51 return *(uint16_t *)reg->data;
52 case 4:
53 return *(uint32_t *)reg->data;
54 case 8:
55 return *(uint64_t *)reg->data;
56 default:
57 g_assert_not_reached();
58 }
59 return 0; /* unreachable */
60 }
61
62 void register_write(RegisterInfo *reg, uint64_t val, uint64_t we,
63 const char *prefix, bool debug)
64 {
65 uint64_t old_val, new_val, test, no_w_mask;
66 const RegisterAccessInfo *ac;
67
68 assert(reg);
69
70 ac = reg->access;
71
72 if (!ac || !ac->name) {
73 qemu_log_mask(LOG_GUEST_ERROR, "%s: write to undefined device state "
74 "(written value: %#" PRIx64 ")\n", prefix, val);
75 return;
76 }
77
78 old_val = reg->data ? register_read_val(reg) : ac->reset;
79
80 test = (old_val ^ val) & ac->rsvd;
81 if (test) {
82 qemu_log_mask(LOG_GUEST_ERROR, "%s: change of value in reserved bit"
83 "fields: %#" PRIx64 ")\n", prefix, test);
84 }
85
86 test = val & ac->unimp;
87 if (test) {
88 qemu_log_mask(LOG_UNIMP,
89 "%s:%s writing %#" PRIx64 " to unimplemented bits:" \
90 " %#" PRIx64 "",
91 prefix, reg->access->name, val, ac->unimp);
92 }
93
94 /* Create the no write mask based on the read only, write to clear and
95 * reserved bit masks.
96 */
97 no_w_mask = ac->ro | ac->w1c | ac->rsvd | ~we;
98 new_val = (val & ~no_w_mask) | (old_val & no_w_mask);
99 new_val &= ~(val & ac->w1c);
100
101 if (ac->pre_write) {
102 new_val = ac->pre_write(reg, new_val);
103 }
104
105 if (debug) {
106 qemu_log("%s:%s: write of value %#" PRIx64 "\n", prefix, ac->name,
107 new_val);
108 }
109
110 register_write_val(reg, new_val);
111
112 if (ac->post_write) {
113 ac->post_write(reg, new_val);
114 }
115 }
116
117 uint64_t register_read(RegisterInfo *reg, uint64_t re, const char* prefix,
118 bool debug)
119 {
120 uint64_t ret;
121 const RegisterAccessInfo *ac;
122
123 assert(reg);
124
125 ac = reg->access;
126 if (!ac || !ac->name) {
127 qemu_log_mask(LOG_GUEST_ERROR, "%s: read from undefined device state\n",
128 prefix);
129 return 0;
130 }
131
132 ret = reg->data ? register_read_val(reg) : ac->reset;
133
134 register_write_val(reg, ret & ~(ac->cor & re));
135
136 /* Mask based on the read enable size */
137 ret &= re;
138
139 if (ac->post_read) {
140 ret = ac->post_read(reg, ret);
141 }
142
143 if (debug) {
144 qemu_log("%s:%s: read of value %#" PRIx64 "\n", prefix,
145 ac->name, ret);
146 }
147
148 return ret;
149 }
150
151 void register_reset(RegisterInfo *reg)
152 {
153 g_assert(reg);
154
155 if (!reg->data || !reg->access) {
156 return;
157 }
158
159 register_write_val(reg, reg->access->reset);
160 }
161
162 void register_init(RegisterInfo *reg)
163 {
164 assert(reg);
165
166 if (!reg->data || !reg->access) {
167 return;
168 }
169
170 object_initialize((void *)reg, sizeof(*reg), TYPE_REGISTER);
171 }
172
173 void register_write_memory(void *opaque, hwaddr addr,
174 uint64_t value, unsigned size)
175 {
176 RegisterInfoArray *reg_array = opaque;
177 RegisterInfo *reg = NULL;
178 uint64_t we;
179 int i;
180
181 for (i = 0; i < reg_array->num_elements; i++) {
182 if (reg_array->r[i]->access->addr == addr) {
183 reg = reg_array->r[i];
184 break;
185 }
186 }
187
188 if (!reg) {
189 qemu_log_mask(LOG_GUEST_ERROR, "Write to unimplemented register at " \
190 "address: %#" PRIx64 "\n", addr);
191 return;
192 }
193
194 /* Generate appropriate write enable mask */
195 if (reg->data_size < size) {
196 we = MAKE_64BIT_MASK(0, reg->data_size * 8);
197 } else {
198 we = MAKE_64BIT_MASK(0, size * 8);
199 }
200
201 register_write(reg, value, we, reg_array->prefix,
202 reg_array->debug);
203 }
204
205 uint64_t register_read_memory(void *opaque, hwaddr addr,
206 unsigned size)
207 {
208 RegisterInfoArray *reg_array = opaque;
209 RegisterInfo *reg = NULL;
210 uint64_t read_val;
211 int i;
212
213 for (i = 0; i < reg_array->num_elements; i++) {
214 if (reg_array->r[i]->access->addr == addr) {
215 reg = reg_array->r[i];
216 break;
217 }
218 }
219
220 if (!reg) {
221 qemu_log_mask(LOG_GUEST_ERROR, "Read to unimplemented register at " \
222 "address: %#" PRIx64 "\n", addr);
223 return 0;
224 }
225
226 read_val = register_read(reg, size * 8, reg_array->prefix,
227 reg_array->debug);
228
229 return extract64(read_val, 0, size * 8);
230 }
231
232 RegisterInfoArray *register_init_block32(DeviceState *owner,
233 const RegisterAccessInfo *rae,
234 int num, RegisterInfo *ri,
235 uint32_t *data,
236 const MemoryRegionOps *ops,
237 bool debug_enabled,
238 uint64_t memory_size)
239 {
240 const char *device_prefix = object_get_typename(OBJECT(owner));
241 RegisterInfoArray *r_array = g_new0(RegisterInfoArray, 1);
242 int i;
243
244 r_array->r = g_new0(RegisterInfo *, num);
245 r_array->num_elements = num;
246 r_array->debug = debug_enabled;
247 r_array->prefix = device_prefix;
248
249 for (i = 0; i < num; i++) {
250 int index = rae[i].addr / 4;
251 RegisterInfo *r = &ri[index];
252
253 *r = (RegisterInfo) {
254 .data = &data[index],
255 .data_size = sizeof(uint32_t),
256 .access = &rae[i],
257 .opaque = owner,
258 };
259 register_init(r);
260
261 r_array->r[i] = r;
262 }
263
264 memory_region_init_io(&r_array->mem, OBJECT(owner), ops, r_array,
265 device_prefix, memory_size);
266
267 return r_array;
268 }
269
270 void register_finalize_block(RegisterInfoArray *r_array)
271 {
272 object_unparent(OBJECT(&r_array->mem));
273 g_free(r_array->r);
274 g_free(r_array);
275 }
276
277 static const TypeInfo register_info = {
278 .name = TYPE_REGISTER,
279 .parent = TYPE_DEVICE,
280 };
281
282 static void register_register_types(void)
283 {
284 type_register_static(&register_info);
285 }
286
287 type_init(register_register_types)