]> git.proxmox.com Git - mirror_qemu.git/blame - hw/misc/mips_itu.c
hw/mips: implement ITC Storage - Control View
[mirror_qemu.git] / hw / misc / mips_itu.c
CommitLineData
34fa7e83
LA
1/*
2 * Inter-Thread Communication Unit emulation.
3 *
4 * Copyright (c) 2016 Imagination Technologies
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "qemu/osdep.h"
21#include "qapi/error.h"
22#include "hw/hw.h"
23#include "hw/sysbus.h"
24#include "sysemu/sysemu.h"
25#include "hw/misc/mips_itu.h"
26
27#define ITC_TAG_ADDRSPACE_SZ (ITC_ADDRESSMAP_NUM * 8)
28/* Initialize as 4kB area to fit all 32 cells with default 128B grain.
29 Storage may be resized by the software. */
30#define ITC_STORAGE_ADDRSPACE_SZ 0x1000
31
32#define ITC_FIFO_NUM_MAX 16
33#define ITC_SEMAPH_NUM_MAX 16
34#define ITC_AM1_NUMENTRIES_OFS 20
35
5924c869
LA
36#define ITC_CELL_TAG_FIFO_DEPTH 28
37#define ITC_CELL_TAG_FIFO_PTR 18
38#define ITC_CELL_TAG_FIFO 17
39#define ITC_CELL_TAG_T 16
40#define ITC_CELL_TAG_F 1
41#define ITC_CELL_TAG_E 0
42
34fa7e83
LA
43#define ITC_AM0_BASE_ADDRESS_MASK 0xFFFFFC00ULL
44#define ITC_AM0_EN_MASK 0x1
45
46#define ITC_AM1_ADDR_MASK_MASK 0x1FC00
47#define ITC_AM1_ENTRY_GRAIN_MASK 0x7
48
5924c869
LA
49typedef enum ITCView {
50 ITCVIEW_BYPASS = 0,
51 ITCVIEW_CONTROL = 1,
52 ITCVIEW_EF_SYNC = 2,
53 ITCVIEW_EF_TRY = 3,
54 ITCVIEW_PV_SYNC = 4,
55 ITCVIEW_PV_TRY = 5
56} ITCView;
57
34fa7e83
LA
58MemoryRegion *mips_itu_get_tag_region(MIPSITUState *itu)
59{
60 return &itu->tag_io;
61}
62
63static uint64_t itc_tag_read(void *opaque, hwaddr addr, unsigned size)
64{
65 MIPSITUState *tag = (MIPSITUState *)opaque;
66 uint64_t index = addr >> 3;
67 uint64_t ret = 0;
68
69 switch (index) {
70 case 0 ... ITC_ADDRESSMAP_NUM:
71 ret = tag->ITCAddressMap[index];
72 break;
73 default:
74 qemu_log_mask(LOG_GUEST_ERROR, "Read 0x%" PRIx64 "\n", addr);
75 break;
76 }
77
78 return ret;
79}
80
81static void itc_reconfigure(MIPSITUState *tag)
82{
83 uint64_t *am = &tag->ITCAddressMap[0];
84 MemoryRegion *mr = &tag->storage_io;
85 hwaddr address = am[0] & ITC_AM0_BASE_ADDRESS_MASK;
86 uint64_t size = (1 << 10) + (am[1] & ITC_AM1_ADDR_MASK_MASK);
87 bool is_enabled = (am[0] & ITC_AM0_EN_MASK) != 0;
88
89 memory_region_transaction_begin();
90 if (!(size & (size - 1))) {
91 memory_region_set_size(mr, size);
92 }
93 memory_region_set_address(mr, address);
94 memory_region_set_enabled(mr, is_enabled);
95 memory_region_transaction_commit();
96}
97
98static void itc_tag_write(void *opaque, hwaddr addr,
99 uint64_t data, unsigned size)
100{
101 MIPSITUState *tag = (MIPSITUState *)opaque;
102 uint64_t *am = &tag->ITCAddressMap[0];
103 uint64_t am_old, mask;
104 uint64_t index = addr >> 3;
105
106 switch (index) {
107 case 0:
108 mask = ITC_AM0_BASE_ADDRESS_MASK | ITC_AM0_EN_MASK;
109 break;
110 case 1:
111 mask = ITC_AM1_ADDR_MASK_MASK | ITC_AM1_ENTRY_GRAIN_MASK;
112 break;
113 default:
114 qemu_log_mask(LOG_GUEST_ERROR, "Bad write 0x%" PRIx64 "\n", addr);
115 return;
116 }
117
118 am_old = am[index];
119 am[index] = (data & mask) | (am_old & ~mask);
120 if (am_old != am[index]) {
121 itc_reconfigure(tag);
122 }
123}
124
125static const MemoryRegionOps itc_tag_ops = {
126 .read = itc_tag_read,
127 .write = itc_tag_write,
128 .impl = {
129 .max_access_size = 8,
130 },
131 .endianness = DEVICE_NATIVE_ENDIAN,
132};
133
134static inline uint32_t get_num_cells(MIPSITUState *s)
135{
136 return s->num_fifo + s->num_semaphores;
137}
138
5924c869
LA
139static inline ITCView get_itc_view(hwaddr addr)
140{
141 return (addr >> 3) & 0xf;
142}
143
144static inline int get_cell_stride_shift(const MIPSITUState *s)
145{
146 /* Minimum interval (for EntryGain = 0) is 128 B */
147 return 7 + (s->ITCAddressMap[1] & ITC_AM1_ENTRY_GRAIN_MASK);
148}
149
150static inline ITCStorageCell *get_cell(MIPSITUState *s,
151 hwaddr addr)
152{
153 uint32_t cell_idx = addr >> get_cell_stride_shift(s);
154 uint32_t num_cells = get_num_cells(s);
155
156 if (cell_idx >= num_cells) {
157 cell_idx = num_cells - 1;
158 }
159
160 return &s->cell[cell_idx];
161}
162
163/* ITC Control View */
164
165static inline uint64_t view_control_read(ITCStorageCell *c)
166{
167 return ((uint64_t)c->tag.FIFODepth << ITC_CELL_TAG_FIFO_DEPTH) |
168 (c->tag.FIFOPtr << ITC_CELL_TAG_FIFO_PTR) |
169 (c->tag.FIFO << ITC_CELL_TAG_FIFO) |
170 (c->tag.T << ITC_CELL_TAG_T) |
171 (c->tag.E << ITC_CELL_TAG_E) |
172 (c->tag.F << ITC_CELL_TAG_F);
173}
174
175static inline void view_control_write(ITCStorageCell *c, uint64_t val)
176{
177 c->tag.T = (val >> ITC_CELL_TAG_T) & 1;
178 c->tag.E = (val >> ITC_CELL_TAG_E) & 1;
179 c->tag.F = (val >> ITC_CELL_TAG_F) & 1;
180
181 if (c->tag.E) {
182 c->tag.FIFOPtr = 0;
183 }
184}
185
186static uint64_t itc_storage_read(void *opaque, hwaddr addr, unsigned size)
187{
188 MIPSITUState *s = (MIPSITUState *)opaque;
189 ITCStorageCell *cell = get_cell(s, addr);
190 ITCView view = get_itc_view(addr);
191 uint64_t ret = -1;
192
193 switch (view) {
194 case ITCVIEW_CONTROL:
195 ret = view_control_read(cell);
196 break;
197 default:
198 qemu_log_mask(LOG_GUEST_ERROR,
199 "itc_storage_read: Bad ITC View %d\n", (int)view);
200 break;
201 }
202
203 return ret;
204}
205
206static void itc_storage_write(void *opaque, hwaddr addr, uint64_t data,
207 unsigned size)
208{
209 MIPSITUState *s = (MIPSITUState *)opaque;
210 ITCStorageCell *cell = get_cell(s, addr);
211 ITCView view = get_itc_view(addr);
212
213 switch (view) {
214 case ITCVIEW_CONTROL:
215 view_control_write(cell, data);
216 break;
217 default:
218 qemu_log_mask(LOG_GUEST_ERROR,
219 "itc_storage_write: Bad ITC View %d\n", (int)view);
220 break;
221 }
222
223}
224
34fa7e83 225static const MemoryRegionOps itc_storage_ops = {
5924c869
LA
226 .read = itc_storage_read,
227 .write = itc_storage_write,
34fa7e83
LA
228 .endianness = DEVICE_NATIVE_ENDIAN,
229};
230
231static void itc_reset_cells(MIPSITUState *s)
232{
233 int i;
234
235 memset(s->cell, 0, get_num_cells(s) * sizeof(s->cell[0]));
236
237 for (i = 0; i < s->num_fifo; i++) {
238 s->cell[i].tag.E = 1;
239 s->cell[i].tag.FIFO = 1;
240 s->cell[i].tag.FIFODepth = ITC_CELL_DEPTH_SHIFT;
241 }
242}
243
244static void mips_itu_init(Object *obj)
245{
246 SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
247 MIPSITUState *s = MIPS_ITU(obj);
248
249 memory_region_init_io(&s->storage_io, OBJECT(s), &itc_storage_ops, s,
250 "mips-itc-storage", ITC_STORAGE_ADDRSPACE_SZ);
251 sysbus_init_mmio(sbd, &s->storage_io);
252
253 memory_region_init_io(&s->tag_io, OBJECT(s), &itc_tag_ops, s,
254 "mips-itc-tag", ITC_TAG_ADDRSPACE_SZ);
255}
256
257static void mips_itu_realize(DeviceState *dev, Error **errp)
258{
259 MIPSITUState *s = MIPS_ITU(dev);
260
261 if (s->num_fifo > ITC_FIFO_NUM_MAX) {
262 error_setg(errp, "Exceed maximum number of FIFO cells: %d",
263 s->num_fifo);
264 return;
265 }
266 if (s->num_semaphores > ITC_SEMAPH_NUM_MAX) {
267 error_setg(errp, "Exceed maximum number of Semaphore cells: %d",
268 s->num_semaphores);
269 return;
270 }
271
272 s->cell = g_new(ITCStorageCell, get_num_cells(s));
273}
274
275static void mips_itu_reset(DeviceState *dev)
276{
277 MIPSITUState *s = MIPS_ITU(dev);
278
279 s->ITCAddressMap[0] = 0;
280 s->ITCAddressMap[1] =
281 ((ITC_STORAGE_ADDRSPACE_SZ - 1) & ITC_AM1_ADDR_MASK_MASK) |
282 (get_num_cells(s) << ITC_AM1_NUMENTRIES_OFS);
283 itc_reconfigure(s);
284
285 itc_reset_cells(s);
286}
287
288static Property mips_itu_properties[] = {
289 DEFINE_PROP_INT32("num-fifo", MIPSITUState, num_fifo,
290 ITC_FIFO_NUM_MAX),
291 DEFINE_PROP_INT32("num-semaphores", MIPSITUState, num_semaphores,
292 ITC_SEMAPH_NUM_MAX),
293 DEFINE_PROP_END_OF_LIST(),
294};
295
296static void mips_itu_class_init(ObjectClass *klass, void *data)
297{
298 DeviceClass *dc = DEVICE_CLASS(klass);
299
300 dc->props = mips_itu_properties;
301 dc->realize = mips_itu_realize;
302 dc->reset = mips_itu_reset;
303}
304
305static const TypeInfo mips_itu_info = {
306 .name = TYPE_MIPS_ITU,
307 .parent = TYPE_SYS_BUS_DEVICE,
308 .instance_size = sizeof(MIPSITUState),
309 .instance_init = mips_itu_init,
310 .class_init = mips_itu_class_init,
311};
312
313static void mips_itu_register_types(void)
314{
315 type_register_static(&mips_itu_info);
316}
317
318type_init(mips_itu_register_types)