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 "qemu/units.h" 22 #include "qemu/log.h" 23 #include "qapi/error.h" 24 #include "cpu.h" 25 #include "exec/exec-all.h" 26 #include "hw/misc/mips_itu.h" 27 28 #define ITC_TAG_ADDRSPACE_SZ (ITC_ADDRESSMAP_NUM * 8) 29 /* Initialize as 4kB area to fit all 32 cells with default 128B grain. 30 Storage may be resized by the software. */ 31 #define ITC_STORAGE_ADDRSPACE_SZ 0x1000 32 33 #define ITC_FIFO_NUM_MAX 16 34 #define ITC_SEMAPH_NUM_MAX 16 35 #define ITC_AM1_NUMENTRIES_OFS 20 36 37 #define ITC_CELL_PV_MAX_VAL 0xFFFF 38 39 #define ITC_CELL_TAG_FIFO_DEPTH 28 40 #define ITC_CELL_TAG_FIFO_PTR 18 41 #define ITC_CELL_TAG_FIFO 17 42 #define ITC_CELL_TAG_T 16 43 #define ITC_CELL_TAG_F 1 44 #define ITC_CELL_TAG_E 0 45 46 #define ITC_AM0_BASE_ADDRESS_MASK 0xFFFFFC00ULL 47 #define ITC_AM0_EN_MASK 0x1 48 49 #define ITC_AM1_ADDR_MASK_MASK 0x1FC00 50 #define ITC_AM1_ENTRY_GRAIN_MASK 0x7 51 52 typedef enum ITCView { 53 ITCVIEW_BYPASS = 0, 54 ITCVIEW_CONTROL = 1, 55 ITCVIEW_EF_SYNC = 2, 56 ITCVIEW_EF_TRY = 3, 57 ITCVIEW_PV_SYNC = 4, 58 ITCVIEW_PV_TRY = 5 59 } ITCView; 60 61 MemoryRegion *mips_itu_get_tag_region(MIPSITUState *itu) 62 { 63 return &itu->tag_io; 64 } 65 66 static uint64_t itc_tag_read(void *opaque, hwaddr addr, unsigned size) 67 { 68 MIPSITUState *tag = (MIPSITUState *)opaque; 69 uint64_t index = addr >> 3; 70 71 if (index >= ITC_ADDRESSMAP_NUM) { 72 qemu_log_mask(LOG_GUEST_ERROR, "Read 0x%" PRIx64 "\n", addr); 73 return 0; 74 } 75 76 return tag->ITCAddressMap[index]; 77 } 78 79 static void itc_reconfigure(MIPSITUState *tag) 80 { 81 uint64_t *am = &tag->ITCAddressMap[0]; 82 MemoryRegion *mr = &tag->storage_io; 83 hwaddr address = am[0] & ITC_AM0_BASE_ADDRESS_MASK; 84 uint64_t size = (1 * KiB) + (am[1] & ITC_AM1_ADDR_MASK_MASK); 85 bool is_enabled = (am[0] & ITC_AM0_EN_MASK) != 0; 86 87 memory_region_transaction_begin(); 88 if (!(size & (size - 1))) { 89 memory_region_set_size(mr, size); 90 } 91 memory_region_set_address(mr, address); 92 memory_region_set_enabled(mr, is_enabled); 93 memory_region_transaction_commit(); 94 } 95 96 static void itc_tag_write(void *opaque, hwaddr addr, 97 uint64_t data, unsigned size) 98 { 99 MIPSITUState *tag = (MIPSITUState *)opaque; 100 uint64_t *am = &tag->ITCAddressMap[0]; 101 uint64_t am_old, mask; 102 uint64_t index = addr >> 3; 103 104 switch (index) { 105 case 0: 106 mask = ITC_AM0_BASE_ADDRESS_MASK | ITC_AM0_EN_MASK; 107 break; 108 case 1: 109 mask = ITC_AM1_ADDR_MASK_MASK | ITC_AM1_ENTRY_GRAIN_MASK; 110 break; 111 default: 112 qemu_log_mask(LOG_GUEST_ERROR, "Bad write 0x%" PRIx64 "\n", addr); 113 return; 114 } 115 116 am_old = am[index]; 117 am[index] = (data & mask) | (am_old & ~mask); 118 if (am_old != am[index]) { 119 itc_reconfigure(tag); 120 } 121 } 122 123 static const MemoryRegionOps itc_tag_ops = { 124 .read = itc_tag_read, 125 .write = itc_tag_write, 126 .impl = { 127 .max_access_size = 8, 128 }, 129 .endianness = DEVICE_NATIVE_ENDIAN, 130 }; 131 132 static inline uint32_t get_num_cells(MIPSITUState *s) 133 { 134 return s->num_fifo + s->num_semaphores; 135 } 136 137 static inline ITCView get_itc_view(hwaddr addr) 138 { 139 return (addr >> 3) & 0xf; 140 } 141 142 static inline int get_cell_stride_shift(const MIPSITUState *s) 143 { 144 /* Minimum interval (for EntryGain = 0) is 128 B */ 145 return 7 + (s->ITCAddressMap[1] & ITC_AM1_ENTRY_GRAIN_MASK); 146 } 147 148 static inline ITCStorageCell *get_cell(MIPSITUState *s, 149 hwaddr addr) 150 { 151 uint32_t cell_idx = addr >> get_cell_stride_shift(s); 152 uint32_t num_cells = get_num_cells(s); 153 154 if (cell_idx >= num_cells) { 155 cell_idx = num_cells - 1; 156 } 157 158 return &s->cell[cell_idx]; 159 } 160 161 static void wake_blocked_threads(ITCStorageCell *c) 162 { 163 CPUState *cs; 164 CPU_FOREACH(cs) { 165 if (cs->halted && (c->blocked_threads & (1ULL << cs->cpu_index))) { 166 cpu_interrupt(cs, CPU_INTERRUPT_WAKE); 167 } 168 } 169 c->blocked_threads = 0; 170 } 171 172 static void QEMU_NORETURN block_thread_and_exit(ITCStorageCell *c) 173 { 174 c->blocked_threads |= 1ULL << current_cpu->cpu_index; 175 current_cpu->halted = 1; 176 current_cpu->exception_index = EXCP_HLT; 177 cpu_loop_exit_restore(current_cpu, current_cpu->mem_io_pc); 178 } 179 180 /* ITC Bypass View */ 181 182 static inline uint64_t view_bypass_read(ITCStorageCell *c) 183 { 184 if (c->tag.FIFO) { 185 return c->data[c->fifo_out]; 186 } else { 187 return c->data[0]; 188 } 189 } 190 191 static inline void view_bypass_write(ITCStorageCell *c, uint64_t val) 192 { 193 if (c->tag.FIFO && (c->tag.FIFOPtr > 0)) { 194 int idx = (c->fifo_out + c->tag.FIFOPtr - 1) % ITC_CELL_DEPTH; 195 c->data[idx] = val; 196 } 197 198 /* ignore a write to the semaphore cell */ 199 } 200 201 /* ITC Control View */ 202 203 static inline uint64_t view_control_read(ITCStorageCell *c) 204 { 205 return ((uint64_t)c->tag.FIFODepth << ITC_CELL_TAG_FIFO_DEPTH) | 206 (c->tag.FIFOPtr << ITC_CELL_TAG_FIFO_PTR) | 207 (c->tag.FIFO << ITC_CELL_TAG_FIFO) | 208 (c->tag.T << ITC_CELL_TAG_T) | 209 (c->tag.E << ITC_CELL_TAG_E) | 210 (c->tag.F << ITC_CELL_TAG_F); 211 } 212 213 static inline void view_control_write(ITCStorageCell *c, uint64_t val) 214 { 215 c->tag.T = (val >> ITC_CELL_TAG_T) & 1; 216 c->tag.E = (val >> ITC_CELL_TAG_E) & 1; 217 c->tag.F = (val >> ITC_CELL_TAG_F) & 1; 218 219 if (c->tag.E) { 220 c->tag.FIFOPtr = 0; 221 } 222 } 223 224 /* ITC Empty/Full View */ 225 226 static uint64_t view_ef_common_read(ITCStorageCell *c, bool blocking) 227 { 228 uint64_t ret = 0; 229 230 if (!c->tag.FIFO) { 231 return 0; 232 } 233 234 c->tag.F = 0; 235 236 if (blocking && c->tag.E) { 237 block_thread_and_exit(c); 238 } 239 240 if (c->blocked_threads) { 241 wake_blocked_threads(c); 242 } 243 244 if (c->tag.FIFOPtr > 0) { 245 ret = c->data[c->fifo_out]; 246 c->fifo_out = (c->fifo_out + 1) % ITC_CELL_DEPTH; 247 c->tag.FIFOPtr--; 248 } 249 250 if (c->tag.FIFOPtr == 0) { 251 c->tag.E = 1; 252 } 253 254 return ret; 255 } 256 257 static uint64_t view_ef_sync_read(ITCStorageCell *c) 258 { 259 return view_ef_common_read(c, true); 260 } 261 262 static uint64_t view_ef_try_read(ITCStorageCell *c) 263 { 264 return view_ef_common_read(c, false); 265 } 266 267 static inline void view_ef_common_write(ITCStorageCell *c, uint64_t val, 268 bool blocking) 269 { 270 if (!c->tag.FIFO) { 271 return; 272 } 273 274 c->tag.E = 0; 275 276 if (blocking && c->tag.F) { 277 block_thread_and_exit(c); 278 } 279 280 if (c->blocked_threads) { 281 wake_blocked_threads(c); 282 } 283 284 if (c->tag.FIFOPtr < ITC_CELL_DEPTH) { 285 int idx = (c->fifo_out + c->tag.FIFOPtr) % ITC_CELL_DEPTH; 286 c->data[idx] = val; 287 c->tag.FIFOPtr++; 288 } 289 290 if (c->tag.FIFOPtr == ITC_CELL_DEPTH) { 291 c->tag.F = 1; 292 } 293 } 294 295 static void view_ef_sync_write(ITCStorageCell *c, uint64_t val) 296 { 297 view_ef_common_write(c, val, true); 298 } 299 300 static void view_ef_try_write(ITCStorageCell *c, uint64_t val) 301 { 302 view_ef_common_write(c, val, false); 303 } 304 305 /* ITC P/V View */ 306 307 static uint64_t view_pv_common_read(ITCStorageCell *c, bool blocking) 308 { 309 uint64_t ret = c->data[0]; 310 311 if (c->tag.FIFO) { 312 return 0; 313 } 314 315 if (c->data[0] > 0) { 316 c->data[0]--; 317 } else if (blocking) { 318 block_thread_and_exit(c); 319 } 320 321 return ret; 322 } 323 324 static uint64_t view_pv_sync_read(ITCStorageCell *c) 325 { 326 return view_pv_common_read(c, true); 327 } 328 329 static uint64_t view_pv_try_read(ITCStorageCell *c) 330 { 331 return view_pv_common_read(c, false); 332 } 333 334 static inline void view_pv_common_write(ITCStorageCell *c) 335 { 336 if (c->tag.FIFO) { 337 return; 338 } 339 340 if (c->data[0] < ITC_CELL_PV_MAX_VAL) { 341 c->data[0]++; 342 } 343 344 if (c->blocked_threads) { 345 wake_blocked_threads(c); 346 } 347 } 348 349 static void view_pv_sync_write(ITCStorageCell *c) 350 { 351 view_pv_common_write(c); 352 } 353 354 static void view_pv_try_write(ITCStorageCell *c) 355 { 356 view_pv_common_write(c); 357 } 358 359 static uint64_t itc_storage_read(void *opaque, hwaddr addr, unsigned size) 360 { 361 MIPSITUState *s = (MIPSITUState *)opaque; 362 ITCStorageCell *cell = get_cell(s, addr); 363 ITCView view = get_itc_view(addr); 364 uint64_t ret = -1; 365 366 switch (view) { 367 case ITCVIEW_BYPASS: 368 ret = view_bypass_read(cell); 369 break; 370 case ITCVIEW_CONTROL: 371 ret = view_control_read(cell); 372 break; 373 case ITCVIEW_EF_SYNC: 374 ret = view_ef_sync_read(cell); 375 break; 376 case ITCVIEW_EF_TRY: 377 ret = view_ef_try_read(cell); 378 break; 379 case ITCVIEW_PV_SYNC: 380 ret = view_pv_sync_read(cell); 381 break; 382 case ITCVIEW_PV_TRY: 383 ret = view_pv_try_read(cell); 384 break; 385 default: 386 qemu_log_mask(LOG_GUEST_ERROR, 387 "itc_storage_read: Bad ITC View %d\n", (int)view); 388 break; 389 } 390 391 return ret; 392 } 393 394 static void itc_storage_write(void *opaque, hwaddr addr, uint64_t data, 395 unsigned size) 396 { 397 MIPSITUState *s = (MIPSITUState *)opaque; 398 ITCStorageCell *cell = get_cell(s, addr); 399 ITCView view = get_itc_view(addr); 400 401 switch (view) { 402 case ITCVIEW_BYPASS: 403 view_bypass_write(cell, data); 404 break; 405 case ITCVIEW_CONTROL: 406 view_control_write(cell, data); 407 break; 408 case ITCVIEW_EF_SYNC: 409 view_ef_sync_write(cell, data); 410 break; 411 case ITCVIEW_EF_TRY: 412 view_ef_try_write(cell, data); 413 break; 414 case ITCVIEW_PV_SYNC: 415 view_pv_sync_write(cell); 416 break; 417 case ITCVIEW_PV_TRY: 418 view_pv_try_write(cell); 419 break; 420 default: 421 qemu_log_mask(LOG_GUEST_ERROR, 422 "itc_storage_write: Bad ITC View %d\n", (int)view); 423 break; 424 } 425 426 } 427 428 static const MemoryRegionOps itc_storage_ops = { 429 .read = itc_storage_read, 430 .write = itc_storage_write, 431 .endianness = DEVICE_NATIVE_ENDIAN, 432 }; 433 434 static void itc_reset_cells(MIPSITUState *s) 435 { 436 int i; 437 438 memset(s->cell, 0, get_num_cells(s) * sizeof(s->cell[0])); 439 440 for (i = 0; i < s->num_fifo; i++) { 441 s->cell[i].tag.E = 1; 442 s->cell[i].tag.FIFO = 1; 443 s->cell[i].tag.FIFODepth = ITC_CELL_DEPTH_SHIFT; 444 } 445 } 446 447 static void mips_itu_init(Object *obj) 448 { 449 SysBusDevice *sbd = SYS_BUS_DEVICE(obj); 450 MIPSITUState *s = MIPS_ITU(obj); 451 452 memory_region_init_io(&s->storage_io, OBJECT(s), &itc_storage_ops, s, 453 "mips-itc-storage", ITC_STORAGE_ADDRSPACE_SZ); 454 sysbus_init_mmio(sbd, &s->storage_io); 455 456 memory_region_init_io(&s->tag_io, OBJECT(s), &itc_tag_ops, s, 457 "mips-itc-tag", ITC_TAG_ADDRSPACE_SZ); 458 } 459 460 static void mips_itu_realize(DeviceState *dev, Error **errp) 461 { 462 MIPSITUState *s = MIPS_ITU(dev); 463 464 if (s->num_fifo > ITC_FIFO_NUM_MAX) { 465 error_setg(errp, "Exceed maximum number of FIFO cells: %d", 466 s->num_fifo); 467 return; 468 } 469 if (s->num_semaphores > ITC_SEMAPH_NUM_MAX) { 470 error_setg(errp, "Exceed maximum number of Semaphore cells: %d", 471 s->num_semaphores); 472 return; 473 } 474 475 s->cell = g_new(ITCStorageCell, get_num_cells(s)); 476 } 477 478 static void mips_itu_reset(DeviceState *dev) 479 { 480 MIPSITUState *s = MIPS_ITU(dev); 481 482 s->ITCAddressMap[0] = 0; 483 s->ITCAddressMap[1] = 484 ((ITC_STORAGE_ADDRSPACE_SZ - 1) & ITC_AM1_ADDR_MASK_MASK) | 485 (get_num_cells(s) << ITC_AM1_NUMENTRIES_OFS); 486 itc_reconfigure(s); 487 488 itc_reset_cells(s); 489 } 490 491 static Property mips_itu_properties[] = { 492 DEFINE_PROP_INT32("num-fifo", MIPSITUState, num_fifo, 493 ITC_FIFO_NUM_MAX), 494 DEFINE_PROP_INT32("num-semaphores", MIPSITUState, num_semaphores, 495 ITC_SEMAPH_NUM_MAX), 496 DEFINE_PROP_END_OF_LIST(), 497 }; 498 499 static void mips_itu_class_init(ObjectClass *klass, void *data) 500 { 501 DeviceClass *dc = DEVICE_CLASS(klass); 502 503 dc->props = mips_itu_properties; 504 dc->realize = mips_itu_realize; 505 dc->reset = mips_itu_reset; 506 } 507 508 static const TypeInfo mips_itu_info = { 509 .name = TYPE_MIPS_ITU, 510 .parent = TYPE_SYS_BUS_DEVICE, 511 .instance_size = sizeof(MIPSITUState), 512 .instance_init = mips_itu_init, 513 .class_init = mips_itu_class_init, 514 }; 515 516 static void mips_itu_register_types(void) 517 { 518 type_register_static(&mips_itu_info); 519 } 520 521 type_init(mips_itu_register_types) 522