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