]> Git Repo - qemu.git/blobdiff - hw/misc/mips_itu.c
hw/misc/edu: add msi_uninit() for pci_edu_uninit()
[qemu.git] / hw / misc / mips_itu.c
index 24a147400a00e5ecc7c3d1f97f0d74b62bdebe77..43bbec46cf5593e2e4219a3959065427b0d4777c 100644 (file)
  */
 
 #include "qemu/osdep.h"
+#include "qemu/units.h"
+#include "qemu/log.h"
 #include "qapi/error.h"
-#include "hw/hw.h"
-#include "hw/sysbus.h"
-#include "sysemu/sysemu.h"
+#include "cpu.h"
+#include "exec/exec-all.h"
 #include "hw/misc/mips_itu.h"
 
 #define ITC_TAG_ADDRSPACE_SZ (ITC_ADDRESSMAP_NUM * 8)
@@ -33,6 +34,8 @@
 #define ITC_SEMAPH_NUM_MAX 16
 #define ITC_AM1_NUMENTRIES_OFS 20
 
+#define ITC_CELL_PV_MAX_VAL 0xFFFF
+
 #define ITC_CELL_TAG_FIFO_DEPTH 28
 #define ITC_CELL_TAG_FIFO_PTR 18
 #define ITC_CELL_TAG_FIFO 17
@@ -64,18 +67,13 @@ static uint64_t itc_tag_read(void *opaque, hwaddr addr, unsigned size)
 {
     MIPSITUState *tag = (MIPSITUState *)opaque;
     uint64_t index = addr >> 3;
-    uint64_t ret = 0;
 
-    switch (index) {
-    case 0 ... ITC_ADDRESSMAP_NUM:
-        ret = tag->ITCAddressMap[index];
-        break;
-    default:
+    if (index >= ITC_ADDRESSMAP_NUM) {
         qemu_log_mask(LOG_GUEST_ERROR, "Read 0x%" PRIx64 "\n", addr);
-        break;
+        return 0;
     }
 
-    return ret;
+    return tag->ITCAddressMap[index];
 }
 
 static void itc_reconfigure(MIPSITUState *tag)
@@ -83,7 +81,7 @@ static void itc_reconfigure(MIPSITUState *tag)
     uint64_t *am = &tag->ITCAddressMap[0];
     MemoryRegion *mr = &tag->storage_io;
     hwaddr address = am[0] & ITC_AM0_BASE_ADDRESS_MASK;
-    uint64_t size = (1 << 10) + (am[1] & ITC_AM1_ADDR_MASK_MASK);
+    uint64_t size = (1 * KiB) + (am[1] & ITC_AM1_ADDR_MASK_MASK);
     bool is_enabled = (am[0] & ITC_AM0_EN_MASK) != 0;
 
     memory_region_transaction_begin();
@@ -174,10 +172,30 @@ static void wake_blocked_threads(ITCStorageCell *c)
 static void QEMU_NORETURN block_thread_and_exit(ITCStorageCell *c)
 {
     c->blocked_threads |= 1ULL << current_cpu->cpu_index;
-    cpu_restore_state(current_cpu, current_cpu->mem_io_pc);
     current_cpu->halted = 1;
     current_cpu->exception_index = EXCP_HLT;
-    cpu_loop_exit(current_cpu);
+    cpu_loop_exit_restore(current_cpu, current_cpu->mem_io_pc);
+}
+
+/* ITC Bypass View */
+
+static inline uint64_t view_bypass_read(ITCStorageCell *c)
+{
+    if (c->tag.FIFO) {
+        return c->data[c->fifo_out];
+    } else {
+        return c->data[0];
+    }
+}
+
+static inline void view_bypass_write(ITCStorageCell *c, uint64_t val)
+{
+    if (c->tag.FIFO && (c->tag.FIFOPtr > 0)) {
+        int idx = (c->fifo_out + c->tag.FIFOPtr - 1) % ITC_CELL_DEPTH;
+        c->data[idx] = val;
+    }
+
+    /* ignore a write to the semaphore cell */
 }
 
 /* ITC Control View */
@@ -284,6 +302,60 @@ static void view_ef_try_write(ITCStorageCell *c, uint64_t val)
     view_ef_common_write(c, val, false);
 }
 
+/* ITC P/V View */
+
+static uint64_t view_pv_common_read(ITCStorageCell *c, bool blocking)
+{
+    uint64_t ret = c->data[0];
+
+    if (c->tag.FIFO) {
+        return 0;
+    }
+
+    if (c->data[0] > 0) {
+        c->data[0]--;
+    } else if (blocking) {
+        block_thread_and_exit(c);
+    }
+
+    return ret;
+}
+
+static uint64_t view_pv_sync_read(ITCStorageCell *c)
+{
+    return view_pv_common_read(c, true);
+}
+
+static uint64_t view_pv_try_read(ITCStorageCell *c)
+{
+    return view_pv_common_read(c, false);
+}
+
+static inline void view_pv_common_write(ITCStorageCell *c)
+{
+    if (c->tag.FIFO) {
+        return;
+    }
+
+    if (c->data[0] < ITC_CELL_PV_MAX_VAL) {
+        c->data[0]++;
+    }
+
+    if (c->blocked_threads) {
+        wake_blocked_threads(c);
+    }
+}
+
+static void view_pv_sync_write(ITCStorageCell *c)
+{
+    view_pv_common_write(c);
+}
+
+static void view_pv_try_write(ITCStorageCell *c)
+{
+    view_pv_common_write(c);
+}
+
 static uint64_t itc_storage_read(void *opaque, hwaddr addr, unsigned size)
 {
     MIPSITUState *s = (MIPSITUState *)opaque;
@@ -292,6 +364,9 @@ static uint64_t itc_storage_read(void *opaque, hwaddr addr, unsigned size)
     uint64_t ret = -1;
 
     switch (view) {
+    case ITCVIEW_BYPASS:
+        ret = view_bypass_read(cell);
+        break;
     case ITCVIEW_CONTROL:
         ret = view_control_read(cell);
         break;
@@ -301,6 +376,12 @@ static uint64_t itc_storage_read(void *opaque, hwaddr addr, unsigned size)
     case ITCVIEW_EF_TRY:
         ret = view_ef_try_read(cell);
         break;
+    case ITCVIEW_PV_SYNC:
+        ret = view_pv_sync_read(cell);
+        break;
+    case ITCVIEW_PV_TRY:
+        ret = view_pv_try_read(cell);
+        break;
     default:
         qemu_log_mask(LOG_GUEST_ERROR,
                       "itc_storage_read: Bad ITC View %d\n", (int)view);
@@ -318,6 +399,9 @@ static void itc_storage_write(void *opaque, hwaddr addr, uint64_t data,
     ITCView view = get_itc_view(addr);
 
     switch (view) {
+    case ITCVIEW_BYPASS:
+        view_bypass_write(cell, data);
+        break;
     case ITCVIEW_CONTROL:
         view_control_write(cell, data);
         break;
@@ -327,6 +411,12 @@ static void itc_storage_write(void *opaque, hwaddr addr, uint64_t data,
     case ITCVIEW_EF_TRY:
         view_ef_try_write(cell, data);
         break;
+    case ITCVIEW_PV_SYNC:
+        view_pv_sync_write(cell);
+        break;
+    case ITCVIEW_PV_TRY:
+        view_pv_try_write(cell);
+        break;
     default:
         qemu_log_mask(LOG_GUEST_ERROR,
                       "itc_storage_write: Bad ITC View %d\n", (int)view);
This page took 0.024038 seconds and 4 git commands to generate.